Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/elmergrid/src/egmesh.c
3196 views
1
/*
2
ElmerGrid - A simple mesh generation and manipulation utility
3
Copyright (C) 1995- , CSC - IT Center for Science Ltd.
4
5
Author: Peter Raback
6
Email: [email protected]
7
Address: CSC - IT Center for Science Ltd.
8
Keilaranta 14
9
02101 Espoo, Finland
10
11
This program is free software; you can redistribute it and/or
12
modify it under the terms of the GNU General Public License
13
as published by the Free Software Foundation; either version 2
14
of the License, or (at your option) any later version.
15
16
This program is distributed in the hope that it will be useful,
17
but WITHOUT ANY WARRANTY; without even the implied warranty of
18
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
19
GNU General Public License for more details.
20
21
You should have received a copy of the GNU General Public License
22
along with this program; if not, write to the Free Software
23
Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
24
*/
25
26
/* --------------------------: egmesh.c :----------------------------
27
28
This module includes subroutines that formulate the mesh into structures
29
more useful for the user. These are the functions that should be used for
30
assembling. The routines usually operate on structures FemType and
31
BoundaryType.
32
*/
33
34
#include <stdio.h>
35
#include <string.h>
36
#include <stdlib.h>
37
#include <math.h>
38
#include <limits.h>
39
40
#include "egutils.h"
41
#include "egdef.h"
42
#include "egtypes.h"
43
#include "egnative.h"
44
#include "egmesh.h"
45
46
#define DEBUG 0
47
48
49
void GetElementInfo(int element,struct FemType *data,
50
Real *globalcoord,int *ind,int *material)
51
/* For a given element gives the coordinates and index for the knot.
52
This subroutine uses the standard formulation which uses up more
53
memory, but is easier to understand. It requires that the knots
54
must first be stored in struct FemType.
55
*/
56
{
57
int i,indi,nodesd2;
58
nodesd2 = data->elementtypes[element]%100;
59
60
for(i=0;i<nodesd2;i++) {
61
indi = ind[i] = data->topology[element][i];
62
globalcoord[i] = data->x[indi];
63
globalcoord[i+nodesd2] = data->y[indi];
64
}
65
(*material) = data->material[element];
66
}
67
68
int GetElementDimension(int elementtype)
69
{
70
int elemdim;
71
72
elemdim = 0;
73
74
switch (elementtype / 100) {
75
case 1:
76
elemdim = 0;
77
break;
78
case 2:
79
elemdim = 1;
80
break;
81
case 3:
82
case 4:
83
elemdim = 2;
84
break;
85
case 5:
86
case 6:
87
case 7:
88
case 8:
89
elemdim = 3;
90
break;
91
default:
92
printf("GetElementDimension: unknown elementtype %d\n",elementtype);
93
94
}
95
return(elemdim);
96
}
97
98
99
int GetMaxElementType(struct FemType *data)
100
{
101
int i,maxelementtype;
102
103
maxelementtype = data->elementtypes[1];
104
for(i=1;i<=data->noelements;i++)
105
if(data->elementtypes[i] > maxelementtype)
106
maxelementtype = data->elementtypes[i];
107
108
return(maxelementtype);
109
}
110
111
112
int GetMinElementType(struct FemType *data)
113
{
114
int i,minelementtype;
115
116
minelementtype = data->elementtypes[1];
117
for(i=1;i<=data->noelements;i++)
118
if(data->elementtypes[i] < minelementtype)
119
minelementtype = data->elementtypes[i];
120
121
return(minelementtype);
122
}
123
124
125
int GetMaxElementDimension(struct FemType *data)
126
{
127
int maxelementtype,elemdim;
128
129
maxelementtype = GetMaxElementType(data);
130
elemdim = GetElementDimension(maxelementtype);
131
return(elemdim);
132
}
133
134
135
int GetMaxBodyIndex(struct FemType *data) {
136
int i,maxind;
137
138
maxind = 0;
139
for(i=1; i <= data->noelements; i++)
140
maxind = MAX(maxind, data->material[i]);
141
return(maxind);
142
}
143
144
int GetMaxBCIndex(struct BoundaryType *bound) {
145
int i,j,maxind;
146
147
maxind = 0;
148
for(j=0;j < MAXBOUNDARIES;j++) {
149
if(bound[j].created == FALSE) continue;
150
if(bound[j].nosides == 0) continue;
151
152
for(i=1; i <= bound[j].nosides; i++)
153
maxind = MAX(maxind, bound[j].types[i]);
154
}
155
return(maxind);
156
}
157
158
159
160
161
int GetCoordinateDimension(struct FemType *data,int info)
162
{
163
int i,j,noknots,coorddim;
164
int coordis;
165
Real *coord;
166
Real epsilon = 1.0e-20;
167
168
noknots = data->noknots;
169
coorddim = 0;
170
171
for(j=3;j>=1;j--) {
172
coordis = FALSE;
173
if( j==1 )
174
coord = data->x;
175
else if( j==2 )
176
coord = data->y;
177
else
178
coord = data->z;
179
180
for(i=1;i<=noknots;i++)
181
if( fabs( coord[i] ) > epsilon ) {
182
coordis = TRUE;
183
break;
184
}
185
if( coordis ) coorddim = MAX( coorddim, j );
186
}
187
if(info) printf("Coordinates defined in %d dimensions\n",coorddim);
188
189
return(coorddim);
190
}
191
192
193
void GetElementSide(int element,int side,int normal,
194
struct FemType *data,int *ind,int *sideelemtype)
195
/* Give the indices of a given side of a given element.
196
The subroutine is valid for 4, 5, 8, 9, 12 and 16
197
node rectangular elements, and 3 and 6 node triangular
198
elements.
199
*/
200
{
201
int i,j,elemtype,*elemind=NULL,sides,ind2[MAXNODESD2];
202
203
/* if(element < 1 || element > data->noelements ) {
204
printf("Invalid index for element: %d\n",element);
205
bigerror("Cannot continue");
206
} */
207
208
elemtype = data->elementtypes[element];
209
elemind = data->topology[element];
210
sides = elemtype/100;
211
*sideelemtype = 0;
212
213
if(side < 0 && sides > 4)
214
side = -(side+1);
215
216
switch (elemtype) {
217
case 202:
218
case 203:
219
case 204:
220
*sideelemtype = 101;
221
ind[0] = elemind[side];
222
break;
223
224
case 303: /* Linear triangle */
225
if(side < 3) {
226
*sideelemtype = 202;
227
ind[0] = elemind[side];
228
ind[1] = elemind[(side+1)%3];
229
}
230
else if( side < 6 ) {
231
*sideelemtype = 101;
232
ind[0] = elemind[side-3];
233
}
234
break;
235
236
case 306: /* 2nd order triangle */
237
if(side < 3) {
238
*sideelemtype = 203;
239
ind[0] = elemind[side];
240
ind[1] = elemind[(side+1)%3];
241
ind[2] = elemind[side+3];
242
}
243
else if( side < 9 ) {
244
*sideelemtype = 101;
245
ind[0] = elemind[side-3];
246
}
247
break;
248
249
case 310: /* 3rd order triangle */
250
if(side < 3) {
251
*sideelemtype = 204;
252
ind[0] = elemind[side];
253
ind[1] = elemind[(side+1)%3];
254
ind[2] = elemind[2*side+3];
255
ind[3] = elemind[2*side+4];
256
}
257
else if( side < 13) {
258
*sideelemtype = 101;
259
ind[0] = elemind[side-3];
260
}
261
break;
262
263
case 404: /* Linear quadrilateral */
264
if(side < 4) {
265
*sideelemtype = 202;
266
ind[0] = elemind[side];
267
ind[1] = elemind[(side+1)%4];
268
}
269
else if(side < 8) {
270
*sideelemtype = 101;
271
ind[0] = elemind[side-4];
272
}
273
break;
274
275
case 405:
276
if(side < 4) {
277
*sideelemtype = 202;
278
ind[0] = elemind[side];
279
ind[1] = elemind[(side+1)%4];
280
}
281
else if(side < 9) {
282
*sideelemtype = 101;
283
ind[0] = elemind[side-4];
284
}
285
break;
286
287
288
case 408: /* 2nd order quadrilateral */
289
if(side < 4) {
290
*sideelemtype = 203;
291
ind[0] = elemind[side];
292
ind[1] = elemind[(side+1)%4];
293
ind[2] = elemind[side+4];
294
}
295
else if(side < 12) {
296
*sideelemtype = 101;
297
ind[0] = elemind[side-4];
298
}
299
break;
300
301
case 409:
302
if(side < 4) {
303
*sideelemtype = 203;
304
ind[0] = elemind[side];
305
ind[1] = elemind[(side+1)%4];
306
ind[2] = elemind[side+4];
307
}
308
else if(side < 13) {
309
*sideelemtype = 101;
310
ind[0] = elemind[side-4];
311
}
312
break;
313
314
case 412: /* 3rd order quadrilateral */
315
if(side < 4) {
316
*sideelemtype = 204;
317
ind[0] = elemind[side];
318
ind[1] = elemind[(side+1)%4];
319
ind[2] = elemind[2*side+4];
320
ind[3] = elemind[2*side+5];
321
}
322
else if(side < 16) {
323
*sideelemtype = 101;
324
ind[0] = elemind[side-4];
325
}
326
break;
327
328
case 416:
329
if(side < 4) {
330
*sideelemtype = 204;
331
ind[0] = elemind[side];
332
ind[1] = elemind[(side+1)%4];
333
ind[2] = elemind[2*side+4];
334
ind[3] = elemind[2*side+5];
335
}
336
else if(side < 20) {
337
*sideelemtype = 101;
338
ind[0] = elemind[side-4];
339
}
340
break;
341
342
case 504: /* Linear tetrahedron */
343
if(side < 4) {
344
*sideelemtype = 303;
345
if(side < 3) {
346
ind[0] = elemind[side];
347
ind[1] = elemind[(side+1)%3];
348
ind[2] = elemind[3];
349
}
350
if(side == 3) {
351
ind[0] = elemind[0];
352
ind[1] = elemind[2];
353
ind[2] = elemind[1];
354
}
355
}
356
else if(side < 10) {
357
*sideelemtype = 202;
358
if(side < 7) {
359
ind[0] = elemind[side-4];
360
ind[1] = elemind[3];
361
}
362
else {
363
ind[0] = elemind[side-7];
364
ind[1] = elemind[(side-6)%3];
365
}
366
}
367
else if(side < 14) {
368
*sideelemtype = 101;
369
ind[0] = elemind[side-10];
370
}
371
break;
372
373
case 510: /* 2nd order tetrahedron */
374
375
if(side < 4) {
376
*sideelemtype = 306;
377
if(side < 3) {
378
ind[0] = elemind[side];
379
ind[1] = elemind[(side+1)%3];
380
ind[2] = elemind[3];
381
ind[3] = elemind[4+side];
382
ind[4] = elemind[7+(side+1)%3];
383
ind[5] = elemind[7+side];
384
}
385
else if(side == 3) {
386
ind[0] = elemind[0];
387
ind[1] = elemind[1];
388
ind[2] = elemind[2];
389
ind[3] = elemind[4];
390
ind[4] = elemind[5];
391
ind[5] = elemind[6];
392
}
393
}
394
else if(side < 10) {
395
*sideelemtype = 203;
396
if(side < 7) {
397
ind[0] = elemind[side-4];
398
ind[1] = elemind[3];
399
ind[2] = elemind[side+3];
400
}
401
else {
402
ind[0] = elemind[side-7];
403
ind[1] = elemind[(side-6)%3];
404
ind[2] = elemind[side-3];
405
}
406
}
407
else if(side < 20) {
408
*sideelemtype = 101;
409
ind[0] = elemind[side-10];
410
}
411
412
break;
413
414
case 706: /* Linear wedge element */
415
if(side < 3) {
416
*sideelemtype = 404;
417
ind[0] = elemind[side];
418
ind[1] = elemind[(side+1)%3];
419
ind[2] = elemind[(side+1)%3+3];
420
ind[3] = elemind[side+3];
421
}
422
else if (side < 5) {
423
*sideelemtype = 303;
424
for(i=0;i<3;i++)
425
ind[i] = elemind[3*(side-3)+i];
426
}
427
else if(side < 14) {
428
*sideelemtype = 202;
429
if(side < 8) {
430
ind[0] = elemind[side-5];
431
ind[1] = elemind[(side-4)%3];
432
}
433
if(side < 11) {
434
ind[0] = elemind[3+side-8];
435
ind[1] = elemind[3+(side-7)%3];
436
}
437
else {
438
ind[0] = elemind[side-11];
439
ind[1] = elemind[3+side-11];
440
}
441
}
442
else if (side < 20) {
443
*sideelemtype = 101;
444
ind[0] = elemind[side-14];
445
}
446
break;
447
448
case 715: /* Quadratic wedge element */
449
if(side < 3) {
450
*sideelemtype = 408;
451
ind[0] = elemind[side];
452
ind[1] = elemind[(side+1)%3];
453
ind[2] = elemind[(side+1)%3+3];
454
ind[3] = elemind[side+3];
455
ind[4] = elemind[6+side];
456
ind[5] = elemind[9+(side+1)%3];
457
ind[6] = elemind[12+side];
458
ind[7] = elemind[9+side];
459
}
460
else if (side < 5) {
461
*sideelemtype = 306;
462
for(i=0;i<3;i++) {
463
ind[i] = elemind[3*(side-3)+i];
464
ind[i+3] = elemind[3*(side-3)+6+i];
465
}
466
}
467
else if(side < 14) {
468
*sideelemtype = 202;
469
if(side < 8) {
470
ind[0] = elemind[side-5];
471
ind[1] = elemind[(side-4)%3];
472
}
473
if(side < 11) {
474
ind[0] = elemind[3+side-8];
475
ind[1] = elemind[3+(side-7)%3];
476
}
477
else {
478
ind[0] = elemind[side-11];
479
ind[1] = elemind[3+side-11];
480
}
481
}
482
else if (side < 20) {
483
*sideelemtype = 101;
484
ind[0] = elemind[side-14];
485
}
486
break;
487
488
case 605: /* Linear pyramid */
489
if(side < 4) {
490
*sideelemtype = 303;
491
ind[0] = elemind[side];
492
ind[1] = elemind[4];
493
ind[2] = elemind[(side+1)%4];
494
}
495
else if (side < 5) {
496
*sideelemtype = 404;
497
for(i=0;i<4;i++)
498
ind[i] = elemind[i];
499
}
500
else if(side < 13) {
501
*sideelemtype = 202;
502
if(side < 9) {
503
ind[0] = elemind[side-5];
504
ind[1] = elemind[(side-4)%4];
505
}
506
else {
507
ind[0] = elemind[side-9];
508
ind[1] = elemind[4];
509
}
510
}
511
else if(side < 18) {
512
*sideelemtype = 101;
513
ind[0] = elemind[side-13];
514
}
515
break;
516
517
case 613: /* 2nd order pyramid */
518
if(side < 4) {
519
*sideelemtype = 306;
520
ind[0] = elemind[side];
521
ind[1] = elemind[(side+1)%4];
522
ind[2] = elemind[4];
523
524
ind[3] = elemind[side+5];
525
ind[4] = elemind[(side+1)%4+9];
526
ind[5] = elemind[side%4+9];
527
}
528
else if (side == 4) {
529
*sideelemtype = 408;
530
for(i=0;i<4;i++)
531
ind[i] = elemind[i];
532
for(i=0;i<4;i++)
533
ind[i+4] = elemind[i+5];
534
}
535
else if(side < 13) {
536
*sideelemtype = 203;
537
if(side < 9) {
538
ind[0] = elemind[(side-5)];
539
ind[1] = elemind[(side-4)%4];
540
ind[2] = elemind[side];
541
}
542
else {
543
ind[0] = elemind[side-9];
544
ind[1] = elemind[4];
545
ind[2] = elemind[side];
546
}
547
}
548
else if(side < 26) {
549
*sideelemtype = 101;
550
ind[0] = elemind[side-13];
551
}
552
break;
553
554
case 808: /* Linear brick */
555
if(side < 6) {
556
*sideelemtype = 404;
557
if(side < 4) {
558
ind[0] = elemind[side];
559
ind[1] = elemind[(side+1)%4];
560
ind[2] = elemind[(side+1)%4+4];
561
ind[3] = elemind[side+4];
562
}
563
else if(side < 6) {
564
for(i=0;i<4;i++)
565
ind[i] = elemind[4*(side-4)+i];
566
}
567
}
568
else if(side < 18) {
569
*sideelemtype = 202;
570
if(side < 10) {
571
ind[0] = elemind[side-6];
572
ind[1] = elemind[(side-5)%4];
573
}
574
else if(side < 14) {
575
ind[0] = elemind[side-6];
576
ind[1] = elemind[(side-9)%4+4];
577
}
578
else {
579
ind[0] = elemind[side-14];
580
ind[1] = elemind[side-14+4];
581
}
582
}
583
else if(side < 26) {
584
*sideelemtype = 101;
585
ind[0] = elemind[side-18];
586
}
587
break;
588
589
case 820: /* 2nd order brick */
590
if(side < 4) {
591
*sideelemtype = 408;
592
ind[0] = elemind[side];
593
ind[1] = elemind[(side+1)%4];
594
ind[2] = elemind[(side+1)%4+4];
595
ind[3] = elemind[side+4];
596
ind[4] = elemind[8+side];
597
ind[5] = elemind[12+(side+1)%4];
598
ind[6] = elemind[16+side];
599
ind[7] = elemind[12+side];
600
}
601
else if(side < 6) {
602
*sideelemtype = 408;
603
for(i=0;i<4;i++)
604
ind[i] = elemind[4*(side-4)+i];
605
for(i=0;i<4;i++)
606
ind[i+4] = elemind[8*(side-4)+8+i];
607
}
608
break;
609
610
case 827:
611
if(side < 4) {
612
*sideelemtype = 409;
613
ind[0] = elemind[side];
614
ind[1] = elemind[(side+1)%4];
615
ind[2] = elemind[(side+1)%4+4];
616
ind[3] = elemind[side+4];
617
ind[4] = elemind[8+side];
618
ind[5] = elemind[12+(side+1)%4];
619
ind[6] = elemind[16+side];
620
ind[7] = elemind[12+side];
621
ind[8] = elemind[20+side];
622
}
623
else {
624
*sideelemtype = 409;
625
for(i=0;i<4;i++)
626
ind[i] = elemind[4*(side-4)+i];
627
for(i=0;i<4;i++)
628
ind[i+4] = elemind[8*(side-4)+8+i];
629
ind[8] = elemind[20+side];
630
}
631
break;
632
633
default:
634
printf("GetElementSide: unknown elementtype %d (elem=%d,side=%d)\n",elemtype,element,side);
635
bigerror("Cannot continue");
636
}
637
638
if(normal == -1) {
639
if(*sideelemtype == 202 || *sideelemtype == 203 || *sideelemtype == 303 || *sideelemtype == 404) {
640
j = *sideelemtype/100-1;
641
for(i=0;i<=j;i++)
642
ind2[i] = ind[i];
643
for(i=0;i<=j;i++)
644
ind[i] = ind2[j-i];
645
}
646
}
647
}
648
649
650
651
void GetBoundaryElement(int sideind,struct BoundaryType *bound,struct FemType *data,int *ind,int *sideelemtype)
652
{
653
int element,side,normal,i,n;
654
655
if( sideind > bound->nosides ) {
656
*sideelemtype = 0;
657
printf("Side element index %d exceeds size of boundary (%d)\n",sideind,bound->nosides);
658
return;
659
}
660
661
element = bound->parent[sideind];
662
663
664
/*GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2); */
665
666
if(element) {
667
side = bound->side[sideind];
668
normal = bound->normal[sideind];
669
GetElementSide(element,side,normal,data,ind,sideelemtype);
670
}
671
else {
672
*sideelemtype = bound->elementtypes[sideind];
673
674
n = *sideelemtype % 100;
675
676
for(i=0;i<n;i++)
677
ind[i] = bound->topology[sideind][i];
678
679
if(0) {
680
printf("sidelemtype = %d\n",*sideelemtype);
681
printf("ind = ");
682
for(i=0;i<n;i++) printf("%d ",ind[i]);
683
printf("\n");
684
}
685
}
686
}
687
688
689
690
int GetElementFaces(int elemtype)
691
{
692
int basetype=0,elemfaces=0;
693
694
basetype = elemtype / 100;
695
696
switch (basetype) {
697
case 1:
698
elemfaces = 0;
699
break;
700
case 2:
701
elemfaces = 2;
702
break;
703
case 3:
704
elemfaces = 3;
705
break;
706
case 4:
707
elemfaces = 4;
708
break;
709
case 5:
710
elemfaces = 4;
711
break;
712
case 6:
713
elemfaces = 5;
714
break;
715
case 7:
716
elemfaces = 5;
717
break;
718
case 8:
719
elemfaces = 6;
720
break;
721
722
default:
723
printf("GetElementFaces: Unknown elementtype %d\n",elemfaces);
724
}
725
726
return(elemfaces);
727
}
728
729
730
731
732
733
734
int GetElementGraph(int element,int edge,struct FemType *data,int *ind)
735
{
736
int elemtype,basetype,elemnodes;
737
int hit,evenodd,quadratic,side;
738
int *elemind=NULL;
739
740
elemtype = data->elementtypes[element];
741
basetype = elemtype / 100;
742
elemnodes = elemtype % 100;
743
quadratic = (elemnodes > basetype);
744
elemind = data->topology[element];
745
746
ind[0] = ind[1] = 0;
747
748
if(quadratic)
749
side = edge / 2;
750
else
751
side = edge;
752
753
754
switch (basetype) {
755
case 2:
756
if(side == 0) {
757
ind[0] = elemind[0];
758
ind[1] = elemind[1];
759
}
760
break;
761
case 3:
762
if(side < 3) {
763
ind[0] = elemind[side];
764
ind[1] = elemind[(side+1)%3];
765
}
766
break;
767
case 4:
768
if(side < 4) {
769
ind[0] = elemind[side];
770
ind[1] = elemind[(side+1)%4];
771
}
772
break;
773
case 5:
774
if(side < 3) {
775
ind[0] = elemind[side];
776
ind[1] = elemind[(side+1)%3];
777
}
778
else if(side < 6) {
779
ind[0] = elemind[side-3];
780
ind[1] = elemind[3];
781
}
782
break;
783
case 6:
784
if(side < 4) {
785
ind[0] = elemind[side];
786
ind[1] = elemind[(side+1)%4];
787
}
788
else if(side < 8) {
789
ind[0] = elemind[side-4];
790
ind[1] = elemind[4];
791
}
792
break;
793
case 7:
794
switch(side) {
795
case 0: ind[0]=elemind[0]; ind[1]=elemind[1]; break;
796
case 1: ind[0]=elemind[1]; ind[1]=elemind[2]; break;
797
case 2: ind[0]=elemind[2]; ind[1]=elemind[0]; break;
798
case 3: ind[0]=elemind[3]; ind[1]=elemind[4]; break;
799
case 4: ind[0]=elemind[4]; ind[1]=elemind[5]; break;
800
case 5: ind[0]=elemind[5]; ind[1]=elemind[3]; break;
801
case 6: ind[0]=elemind[0]; ind[1]=elemind[3]; break;
802
case 7: ind[0]=elemind[1]; ind[1]=elemind[4]; break;
803
case 8: ind[0]=elemind[2]; ind[1]=elemind[5]; break;
804
}
805
break;
806
807
case 8:
808
if(side < 4) {
809
ind[0] = elemind[side];
810
ind[1] = elemind[(side+1)%4];
811
}
812
else if(side < 8) {
813
ind[0] = elemind[side-4];
814
ind[1] = elemind[side];
815
}
816
else if(side < 12) {
817
ind[0] = elemind[side-4];
818
ind[1] = elemind[4+(side+1)%4];
819
}
820
break;
821
}
822
823
hit = (ind[0] || ind[1]);
824
825
826
if(hit && quadratic) {
827
evenodd = edge - 2*side;
828
829
switch (basetype) {
830
case 2:
831
ind[evenodd] = elemind[2];
832
break;
833
834
case 3:
835
ind[evenodd] = elemind[side+3];
836
break;
837
838
case 4:
839
ind[evenodd] = elemind[side+4];
840
break;
841
842
case 5:
843
ind[evenodd] = elemind[side+4];
844
break;
845
846
case 6:
847
ind[evenodd] = elemind[side+5];
848
break;
849
850
case 7:
851
ind[evenodd] = elemind[side+6];
852
break;
853
854
case 8:
855
ind[evenodd] = elemind[side+8];
856
break;
857
858
}
859
}
860
861
return(hit);
862
}
863
864
865
866
867
int CalculateIndexwidth(struct FemType *data,int indxis,int *indx)
868
{
869
int i,ind,nonodes,indexwidth;
870
int imax,imin,element;
871
872
/* Calculate the maximum bandwidth */
873
874
indexwidth = 0;
875
876
for(element=1; element <= data->noelements; element++) {
877
imin = data->noknots;
878
imax = 0;
879
nonodes = data->elementtypes[element]%100;
880
for(i=0;i<nonodes;i++) {
881
ind = data->topology[element][i];
882
if(indxis) ind = indx[ind];
883
if(ind == 0) continue;
884
if(ind > imax) imax = ind;
885
if(ind < imin) imin = ind;
886
}
887
if(imax-imin > indexwidth)
888
indexwidth = imax-imin;
889
}
890
891
if(!indxis) data->indexwidth = indexwidth;
892
return(indexwidth);
893
}
894
895
896
void InitializeKnots(struct FemType *data)
897
{
898
int i;
899
900
data->timesteps = 0;
901
data->noknots = 0;
902
data->noelements = 0;
903
data->coordsystem = COORD_CART2;
904
data->numbering = NUMBER_XY;
905
data->created = FALSE;
906
data->variables = 0;
907
data->maxnodes = 0;
908
data->indexwidth = 0;
909
data->noboundaries = 0;
910
data->mapgeo = 1;
911
data->nocorners = 0;
912
913
data->boundarynamesexist = FALSE;
914
data->bodynamesexist = FALSE;
915
916
data->nodepermexist = FALSE;
917
918
data->nopartitions = 1;
919
data->partitionexist = FALSE;
920
data->periodicexist = FALSE;
921
data->nodeconnectexist = FALSE;
922
data->elemconnectexist = FALSE;
923
924
data->nodalexists = FALSE;
925
/* data->invtopoexists = FALSE; */
926
data->partitiontableexists = FALSE;
927
data->maxpartitiontable = 0;
928
929
data->invtopo.created = FALSE;
930
data->nodalgraph2.created = FALSE;
931
data->dualgraph.created = FALSE;
932
933
934
for(i=0;i<MAXDOFS;i++) {
935
data->edofs[i] = 0;
936
data->bandwidth[i] = 0;
937
strcpy(data->dofname[i],"");
938
}
939
940
for(i=0;i<MAXBODIES;i++) {
941
data->bodyname[i] = NULL;
942
}
943
for(i=0;i<MAXBCS;i++) {
944
data->boundaryname[i] = NULL;
945
}
946
}
947
948
949
void AllocateKnots(struct FemType *data)
950
{
951
int i;
952
953
data->topology = Imatrix(1,data->noelements,0,data->maxnodes-1);
954
data->material = Ivector(1,data->noelements);
955
data->elementtypes = Ivector(1,data->noelements);
956
957
for(i=1;i<=data->noelements;i++)
958
data->material[i] = 0;
959
960
for(i=1;i<=data->noelements;i++)
961
data->elementtypes[i] = 0;
962
963
data->x = Rvector(1,data->noknots);
964
data->y = Rvector(1,data->noknots);
965
data->z = Rvector(1,data->noknots);
966
for(i=1;i<=data->noknots;i++)
967
data->x[i] = data->y[i] = data->z[i] = 0.0;
968
969
data->created = TRUE;
970
971
#if DEBUG
972
printf("Allocated for %d %d-node elements resulting to %d nodes\n",
973
data->noelements,data->maxnodes,data->noknots);
974
#endif
975
}
976
977
978
static void MovePointCircle(Real *lim,int points,Real *coords,
979
Real x,Real y,Real *dx,Real *dy)
980
{
981
int i;
982
Real x0,y0,r,r1,r2,p;
983
984
r2 = fabs(lim[1]-lim[0]);
985
if(r2 > fabs(lim[2]-lim[1]))
986
r2 = fabs(lim[2]-lim[1]);
987
988
for(i=0;i<points/2;i++) {
989
x0 = x-coords[2*i];
990
r1 = fabs(coords[2*i+1]);
991
992
if(fabs(x0) >= r2) continue;
993
y0 = y-(lim[1]+coords[2*i+1]);
994
if(y0 < 0 && lim[0] > lim[1]) continue;
995
if(y0 > 0 && lim[2] < lim[1]) continue;
996
if(fabs(y0) >= r2) continue;
997
r = sqrt(x0*x0+y0*y0);
998
if(r < 1.0e-50) continue;
999
1000
if(fabs(x0) > fabs(y0)) {
1001
p = fabs(x0)/r - 1.0;
1002
if(fabs(x0) <= r1) {
1003
*dx += p*x0;
1004
*dy += p*y0;
1005
}
1006
else if(fabs(x0) <= r2) {
1007
*dx += p*x0*(r2-fabs(x0))/(r2-r1);
1008
*dy += p*y0*(r2-fabs(x0))/(r2-r1);
1009
}
1010
}
1011
else {
1012
p = fabs(y0)/r - 1.0;
1013
if(fabs(y0) <= r1) {
1014
*dx += p*x0;
1015
*dy += p*y0;
1016
}
1017
else if(fabs(y0) <= r2) {
1018
*dx += p*x0*(r2-fabs(y0))/(r2-r1);
1019
*dy += p*y0*(r2-fabs(y0))/(r2-r1);
1020
}
1021
}
1022
}
1023
}
1024
1025
1026
1027
static void MovePointLinear(Real *lim,int points,Real *coords,
1028
Real x,Real y,Real *dx,Real *dy)
1029
{
1030
static int i=0;
1031
Real c,d;
1032
1033
if(y > lim[0] && y < lim[2]) {
1034
1035
1036
if(x <= coords[0]) {
1037
d = coords[1];
1038
}
1039
else if(x >= coords[points-2]) {
1040
d = coords[points-1];
1041
}
1042
else {
1043
i = 1;
1044
while(x > coords[2*i] && i < points/2-1) i++;
1045
c = (coords[2*i+1]-coords[2*i-1])/(coords[2*i]-coords[2*i-2]);
1046
d = coords[2*i-1] + c*(x-coords[2*i-2]);
1047
}
1048
1049
if(y < lim[1])
1050
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1051
else
1052
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1053
}
1054
}
1055
1056
1057
static void MovePointAngle(Real *lim,int points,Real *coords,
1058
Real x,Real y,Real *dx,Real *dz)
1059
{
1060
static int i=0;
1061
Real x1,z1,degs;
1062
1063
degs = FM_PI/180.0;
1064
x1 = z1 = 0.0;
1065
1066
if(y > lim[0] && y < lim[2]) {
1067
if(x <= coords[0]) {
1068
x1 = x;
1069
}
1070
else {
1071
i = 1;
1072
while(x > coords[2*i] && i <= points/2-1) {
1073
x1 = x1 + cos(degs*coords[2*i-1])*(coords[2*i]-coords[2*i-2]);
1074
z1 = z1 + sin(degs*coords[2*i-1])*(coords[2*i]-coords[2*i-2]);
1075
i++;
1076
}
1077
x1 = x1 + cos(degs*coords[2*i-1])*(x-coords[2*i-2]);
1078
z1 = z1 + sin(degs*coords[2*i-1])*(x-coords[2*i-2]);
1079
}
1080
1081
if(y < lim[1]) {
1082
*dx += (x1-x)*(y-lim[0])/(lim[1]-lim[0]);
1083
*dz += z1*(y-lim[0])/(lim[1]-lim[0]);
1084
}
1085
else {
1086
*dx += (x1-x)*(lim[2]-y)/(lim[2]-lim[1]);
1087
*dz += z1*(lim[2]-y)/(lim[2]-lim[1]);
1088
}
1089
}
1090
}
1091
1092
1093
static void MovePointSinus(Real *lim,int points,Real *coords,
1094
Real x,Real y,Real *dx,Real *dy)
1095
{
1096
Real c,d;
1097
1098
if(y > lim[0] && y < lim[2]) {
1099
1100
if(x <= coords[0]) {
1101
d = 0.0;
1102
}
1103
else if(x >= coords[1]) {
1104
d = coords[3]*sin(coords[2]*2.*FM_PI);
1105
}
1106
else {
1107
c = coords[2]*2.*FM_PI/(coords[1]-coords[0]);
1108
d = coords[3]*sin(c*(x-coords[0]));
1109
}
1110
1111
if(y < lim[1])
1112
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1113
else
1114
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1115
}
1116
}
1117
1118
1119
1120
static void MovePointPowerSeries(Real *lim,int points,Real *coords,
1121
Real x,Real y,Real *dx,Real *dy)
1122
{
1123
int i,n;
1124
Real d,t,u;
1125
1126
if(y > lim[0] && y < lim[2]) {
1127
t = x;
1128
if(coords[1] > coords[0]) {
1129
if(t<coords[0]) t = coords[0];
1130
if(t>coords[1]) t = coords[1];
1131
}
1132
else {
1133
if(t>coords[0]) t = coords[0];
1134
if(t<coords[1]) t = coords[1];
1135
}
1136
1137
n = points-2;
1138
u = (t - coords[0])/(coords[1]-coords[0]);
1139
1140
d = 0.0;
1141
for(i=0;i<n;i++) {
1142
d += coords[i+2] * pow(u,i);
1143
}
1144
1145
if(y < lim[1]) {
1146
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1147
}
1148
else {
1149
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1150
}
1151
}
1152
}
1153
1154
1155
static void MovePointPowerSeries2(Real *lim,int points,Real *coords,
1156
Real x,Real y,Real *dx,Real *dy)
1157
{
1158
int i,j,n;
1159
Real d,e,t,u,h;
1160
1161
if(y > lim[0] && y < lim[2]) {
1162
t = x;
1163
if(coords[1] > coords[0]) {
1164
if(t<coords[0]) t = coords[0];
1165
if(t>coords[1]) t = coords[1];
1166
}
1167
else {
1168
if(t>coords[0]) t = coords[0];
1169
if(t<coords[1]) t = coords[1];
1170
}
1171
1172
n = points-2;
1173
u = (t - coords[0])/(coords[1]-coords[0]);
1174
1175
d = 0.0;
1176
1177
d = coords[2];
1178
if(n>=1) d += u * coords[3];
1179
1180
for(i=2;i<n;i++) {
1181
h = 1.0/(i-1);
1182
e = 1.0;
1183
for(j=0;j<i;j++)
1184
e *= (u-j*h);
1185
d += coords[i+2] * e;
1186
}
1187
1188
if(y < lim[1]) {
1189
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1190
}
1191
else {
1192
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1193
}
1194
}
1195
}
1196
1197
1198
1199
static void MovePointPower(Real *lim,int points,Real *coords,
1200
Real x,Real y,Real *dx,Real *dy)
1201
{
1202
static int i=0;
1203
Real c,d;
1204
1205
if(y > lim[0] && y < lim[2]) {
1206
if(x <= coords[0]) {
1207
d = coords[1];
1208
}
1209
else if(x >= coords[points-2]) {
1210
d = coords[points-1];
1211
}
1212
else {
1213
i = 1;
1214
while(x > coords[3*i] && i < points/3-1) i++;
1215
c = (coords[3*i+1]-coords[3*i-2])/pow((coords[3*i]-coords[3*i-3]),coords[3*i-1]);
1216
d = coords[3*i-2] + c*pow((x-coords[3*i-3]),coords[3*i-1]);
1217
}
1218
1219
if(y < lim[1])
1220
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1221
else
1222
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1223
}
1224
}
1225
1226
/* Creates airfoil shapes */
1227
static void MovePointNACAairfoil(Real *lim,int points,Real *coords,
1228
Real x,Real y,Real *dx,Real *dy)
1229
{
1230
Real p,d,t,u;
1231
1232
if(y < lim[0] || y > lim[2]) return;
1233
if(x < coords[0] || x > coords[1]) return;
1234
1235
if(0) {
1236
printf("x=%.3e y=%.3e lim0=%.3e lim2=%.3e\n",x,y,lim[0],lim[2]);
1237
printf("naca: %.3e %.3e %.3e\n",coords[0],coords[1],coords[2]);
1238
}
1239
1240
t = x;
1241
if(coords[1] > coords[0]) {
1242
if(t<coords[0]) t = coords[0];
1243
if(t>coords[1]) t = coords[1];
1244
}
1245
else {
1246
if(t>coords[0]) t = coords[0];
1247
if(t<coords[1]) t = coords[1];
1248
}
1249
1250
u = (t - coords[0])/(coords[1]-coords[0]);
1251
p = 0.2969*sqrt(u) - 0.1260*u - 0.3537*u*u + 0.2843*u*u*u - 0.1015*u*u*u*u;
1252
1253
d = coords[2] * (coords[1]-coords[0]) * p / 0.2;
1254
1255
if(y < lim[1]) {
1256
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1257
}
1258
else {
1259
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1260
}
1261
1262
1263
if(0) printf("d=%.3e p=%.3e u=%.3e dy=%.3e\n",d,p,u,*dy);
1264
}
1265
1266
1267
1268
static void MovePointArc(Real *lim,int points,Real *coords,
1269
Real x,Real y,Real *dx,Real *dy)
1270
{
1271
static int i=0;
1272
Real sx,sy,ss,r,rat,d,x0,y0;
1273
1274
if(y > lim[0] && y < lim[2]) {
1275
if(x <= coords[0]) {
1276
d = coords[1];
1277
}
1278
else if(x >= coords[points-2]) {
1279
d = coords[points-1];
1280
}
1281
else {
1282
i = 1;
1283
while(x > coords[3*i] && i < points/3-1) i++;
1284
sx = 0.5*(coords[3*i]-coords[3*i-3]);
1285
sy = 0.5*(coords[3*i+1]-coords[3*i-2]);
1286
r = coords[3*i-1];
1287
ss = sx*sx+sy*sy;
1288
rat = sqrt(1.0/ss-1.0/(r*r))*r;
1289
x0 = coords[3*i-3] + sx - sy * rat;
1290
y0 = coords[3*i-2] + sy + sx * rat;
1291
d = y0-sqrt(r*r-(x-x0)*(x-x0))*r/fabs(r);
1292
}
1293
1294
if(y < lim[1])
1295
*dy += d*(y-lim[0])/(lim[1]-lim[0]);
1296
else
1297
*dy += d*(lim[2]-y)/(lim[2]-lim[1]);
1298
}
1299
}
1300
1301
1302
1303
void CreateKnots(struct GridType *grid,struct CellType *cell,
1304
struct FemType *data,int noknots,int info)
1305
/* Saves information concerning the knots to a special structure to avoid
1306
repetitious calculations. This should be used unless there is a severe
1307
lack of memory. GridType includes only rectangular 2D elements.
1308
*/
1309
{
1310
Real globalcoord[DIM*MAXNODESD2];
1311
Real maplim[3*MAXMAPPINGS];
1312
int material,nonodes,elemind,elemtype;
1313
int mode,level,maplevel,dim;
1314
int celli,cellj,i,j,k,l,ind[MAXNODESD2];
1315
Real x,y,dx,dy,dz,size,minsize,maxsize;
1316
1317
InitializeKnots(data);
1318
1319
dim = data->dim = grid->dimension;
1320
nonodes = grid->nonodes;
1321
data->maxnodes = grid->nonodes;
1322
data->nocells = grid->nocells;
1323
data->noelements = grid->noelements;
1324
data->coordsystem = grid->coordsystem;
1325
data->numbering = grid->numbering;
1326
data->indexwidth = grid->maxwidth;
1327
data->noknots = MAX(noknots,grid->noknots);
1328
data->noboundaries = grid->noboundaries;
1329
1330
AllocateKnots(data);
1331
minsize = 1.0e20;
1332
1333
if(dim == 1)
1334
elemtype = grid->nonodes + 200;
1335
else
1336
elemtype = grid->nonodes + 400;
1337
1338
for(i=1;i<=data->noelements;i++)
1339
data->elementtypes[i] = elemtype;
1340
1341
/* This numbers the elements the same way the knots are numbered. */
1342
for(cellj=1;cellj<= grid->ycells ;cellj++) { /* cells direction up */
1343
for(j=1; j<=grid->yelems[cellj]; j++) /* lines inside cells */
1344
for(celli=1;celli<= grid->xcells; celli++) /* cells direction right */
1345
if((k=grid->numbered[cellj][celli])) {
1346
material = cell[k].material;
1347
for(i=1; i<=grid->xelems[celli]; i++) {
1348
1349
elemind = GetElementCoordinates(&(cell)[k],i,j,globalcoord,ind);
1350
1351
if(data->noknots == grid->noknots) {
1352
for(l=0;l<nonodes;l++) {
1353
data->topology[elemind][l] = ind[l];
1354
data->x[ind[l]] = globalcoord[l];
1355
data->y[ind[l]] = globalcoord[l+nonodes];
1356
}
1357
data->material[elemind] = material;
1358
1359
}
1360
}
1361
}
1362
}
1363
1364
/* Map the knots as defined in structures grid */
1365
for(k=0;k<grid->mappings;k++) {
1366
j = grid->mappingline[k];
1367
if(grid->mappingtype[k] > 0)
1368
maplim[3*k+1] = grid->y[j];
1369
else if(grid->mappingtype[k] < 0)
1370
maplim[3*k+1] = grid->x[j];
1371
else
1372
continue;
1373
maplim[3*k] = maplim[3*k+1] - grid->mappinglimits[2*k];
1374
maplim[3*k+2] = maplim[3*k+1] + grid->mappinglimits[2*k+1];
1375
}
1376
1377
mode = 0;
1378
if(grid->mappings)
1379
1380
for(level=0;level<10;level++) {
1381
maplevel = FALSE;
1382
for(k=0;k<grid->mappings;k++)
1383
if(abs(grid->mappingtype[k]/10) == level)
1384
maplevel = TRUE;
1385
if(maplevel == FALSE) continue;
1386
1387
if(level >= 5) data->dim = 3;
1388
1389
for(i=1;i<=data->noknots;i++) {
1390
x = data->x[i];
1391
y = data->y[i];
1392
dx = 0.0;
1393
dy = 0.0;
1394
dz = 0.0;
1395
1396
for(k=0;k<grid->mappings;k++) {
1397
mode = grid->mappingtype[k]%10;
1398
switch (mode) {
1399
case 1:
1400
MovePointLinear(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1401
x,y,&dx,&dy);
1402
break;
1403
case 2:
1404
MovePointPower(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1405
x,y,&dx,&dy);
1406
break;
1407
case 3:
1408
MovePointArc(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1409
x,y,&dx,&dy);
1410
break;
1411
case 4:
1412
MovePointCircle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1413
x,y,&dx,&dy);
1414
break;
1415
case 5:
1416
MovePointSinus(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1417
x,y,&dx,&dy);
1418
break;
1419
case 6:
1420
MovePointPowerSeries(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1421
x,y,&dx,&dy);
1422
break;
1423
case 7:
1424
MovePointPowerSeries2(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1425
x,y,&dx,&dy);
1426
break;
1427
case 8:
1428
MovePointAngle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1429
x,y,&dx,&dz);
1430
break;
1431
case 9:
1432
MovePointNACAairfoil(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1433
x,y,&dx,&dy);
1434
break;
1435
1436
1437
case -1:
1438
MovePointLinear(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1439
y,x,&dy,&dx);
1440
break;
1441
case -2:
1442
MovePointPower(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1443
y,x,&dy,&dx);
1444
break;
1445
case -3:
1446
MovePointArc(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1447
y,x,&dy,&dx);
1448
break;
1449
case -4:
1450
MovePointCircle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1451
y,x,&dy,&dx);
1452
break;
1453
case -5:
1454
MovePointSinus(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1455
y,x,&dy,&dx);
1456
break;
1457
case -6:
1458
MovePointPowerSeries(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1459
y,x,&dy,&dx);
1460
break;
1461
case -7:
1462
MovePointPowerSeries2(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1463
y,x,&dy,&dx);
1464
break;
1465
case -8:
1466
MovePointAngle(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1467
y,x,&dy,&dz);
1468
break;
1469
case -9:
1470
MovePointNACAairfoil(&maplim[3*k],grid->mappingpoints[k],grid->mappingparams[k],
1471
y,x,&dy,&dx);
1472
break;
1473
1474
1475
}
1476
}
1477
1478
if(mode == 8 || mode == -8) {
1479
data->x[i] += dx;
1480
data->y[i] += dy;
1481
data->z[i] += dz;
1482
}
1483
else if(level >= 5) {
1484
data->z[i] += dx + dy;
1485
}
1486
else {
1487
data->x[i] += dx;
1488
data->y[i] += dy;
1489
}
1490
}
1491
}
1492
1493
minsize = 1.0e20;
1494
maxsize = 0.0;
1495
1496
for(i=1;i<=data->noelements;i++) {
1497
GetElementInfo(i,data,globalcoord,ind,&material);
1498
1499
dx = globalcoord[0]-globalcoord[1];
1500
dy = globalcoord[nonodes]-globalcoord[nonodes+1];
1501
size = dx*dx+dy*dy;
1502
if(size < minsize) minsize = size;
1503
if(size > maxsize) maxsize = size;
1504
dx = globalcoord[0]-globalcoord[nonodes-1];
1505
dy = globalcoord[nonodes]-globalcoord[2*nonodes-1];
1506
size = dx*dx+dy*dy;
1507
if(size < minsize) minsize = size;
1508
if(size > maxsize) maxsize = size;
1509
}
1510
1511
data->maxsize = sqrt(maxsize);
1512
data->minsize = sqrt(minsize);
1513
1514
if(info) printf("Maximum elementsize is %.3e and minimum %.3e.\n",
1515
data->maxsize,data->minsize);
1516
}
1517
1518
1519
1520
1521
int CreateVariable(struct FemType *data,int variable,int unknowns,
1522
Real value,const char *dofname,int eorder)
1523
/* Create variables for the given data structure */
1524
{
1525
int i,info=FALSE;
1526
int timesteps;
1527
1528
if(variable == 0) return(0);
1529
1530
if(data->created == FALSE) {
1531
if(info) printf("CreateVariable: Knots must first be created!\n");
1532
return(1);
1533
}
1534
timesteps = data->timesteps;
1535
if(timesteps < 1) timesteps = 1;
1536
1537
if(data->edofs[variable] == 0) {
1538
1539
data->variables += 1;
1540
data->edofs[variable] = unknowns;
1541
data->alldofs[variable] = unknowns * data->noknots;
1542
data->bandwidth[variable] = unknowns * data->indexwidth;
1543
data->dofs[variable] = Rvector(1,timesteps * data->alldofs[variable]);
1544
if(info) printf("Created variable %s with %d dofs.\n",
1545
dofname,data->alldofs[variable]);
1546
for(i=1;i<=data->alldofs[variable]*timesteps;i++)
1547
data->dofs[variable][i] = value;
1548
}
1549
else if (data->edofs[variable] == unknowns) {
1550
if(info) printf("CreateVariable: Variable %d exists with correct number of dofs!\n",
1551
variable);
1552
}
1553
else {
1554
if(info) printf("CreateVariable: Variable %d exists with wrong number of dofs!\n",
1555
variable);
1556
return(2);
1557
}
1558
1559
strcpy(data->dofname[variable],dofname);
1560
1561
return(0);
1562
}
1563
1564
1565
1566
void DestroyKnots(struct FemType *data)
1567
{
1568
int i;
1569
1570
if(!data->created) return;
1571
data->created = FALSE;
1572
1573
for(i=0;i<MAXDOFS;i++)
1574
if(data->edofs[i] != 0) {
1575
if(data->edofs[i] > 0)
1576
free_Rvector(data->dofs[i],1,data->alldofs[i]);
1577
data->edofs[i] = 0;
1578
}
1579
1580
free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes-1);
1581
free_Ivector(data->material,1,data->noelements);
1582
free_Ivector(data->elementtypes,1,data->noelements);
1583
1584
free_Rvector(data->x,1,data->noknots);
1585
free_Rvector(data->y,1,data->noknots);
1586
free_Rvector(data->z,1,data->noknots);
1587
1588
data->noknots = 0;
1589
data->noelements = 0;
1590
data->maxnodes = 0;
1591
1592
if(data->nocorners > 0)
1593
free_Ivector(data->corners,1,2*data->nocorners);
1594
}
1595
1596
1597
1598
int CreateBoundary(struct CellType *cell,struct FemType *data,
1599
struct BoundaryType *bound,int material1,int material2,
1600
int solidmat,int boundarytype,int info)
1601
/* This subroutine makes a boundary which includes all sides that separate
1602
two materials that fulfill the conditions in the function call. If both
1603
materials are positive only the sides for which both of the materials
1604
coincide are accepted. In other cases the negative argument tells which
1605
conditions the positive argument should fulfill. Note that on a boundary
1606
where knots are created only for the other material, this material
1607
should be the latter one in the function call (material). The physical
1608
properties (emissivity) of the materials are taken from the one given
1609
by the flag 'solidmat'.
1610
*/
1611
{
1612
int i,side,more,elem,elemind[2],nosides,no,times;
1613
int sidemat,thismat,size,setpoint,dimsides,cellside;
1614
1615
if(data->dim == 1)
1616
dimsides = 2;
1617
else
1618
dimsides = 4;
1619
1620
if(bound->created == TRUE) {
1621
if(info) printf("CreateBoundary: You tried to recreate the boundary!\n");
1622
return(1);
1623
}
1624
if(!data->created) {
1625
if(info) printf("CreateBoundary: You tried to create a boundary before the knots were made.");
1626
return(2);
1627
}
1628
if(material1 < 0 && material2 < 0) {
1629
if(info) printf("CreateBoundary: the material arguments are both negative");
1630
return(3);
1631
}
1632
1633
times = 0;
1634
1635
bound->created = FALSE;
1636
bound->nosides = 0;
1637
if(solidmat >= 2) solidmat -= 2;
1638
1639
startpoint:
1640
1641
/* Go through all elements which have a boundary with the given material, but
1642
are not themselves of that material. First only calculate their amount, then
1643
allocate space and tabulate them. */
1644
nosides = 0;
1645
1646
1647
for(no=1; no <= data->nocells; no++)
1648
for(side=0; side < dimsides; side++) {
1649
1650
if(data->dim == 1)
1651
cellside = 3-2*side;
1652
else
1653
cellside = side;
1654
1655
setpoint = FALSE;
1656
sidemat = cell[no].boundary[cellside];
1657
thismat = cell[no].material;
1658
1659
/* The free boundary conditions are not allowed if the negative
1660
keywords are used. */
1661
1662
/* Either material must be the one defined. */
1663
if( material1 >= 0 && material1 != sidemat) continue;
1664
if( material2 >= 0 && material2 != thismat) continue;
1665
#if 0
1666
printf("mat=[%d %d] sidemat=%d thismat=%d side=%d\n",
1667
material1,material2,sidemat,thismat,side);
1668
#endif
1669
1670
if( material2 == -((side+2)%4+1) && sidemat == material1 &&
1671
sidemat != thismat) setpoint = TRUE;
1672
if( material1 == -(side+1) && thismat == material2 &&
1673
sidemat != thismat) setpoint = TRUE;
1674
1675
if( material1 == MAT_BIGGER && sidemat > material2 ) setpoint = TRUE;
1676
if( material1 == MAT_SMALLER && sidemat < material2 ) setpoint = TRUE;
1677
if( material1 == MAT_ANYTHING && sidemat != material2 ) setpoint = TRUE;
1678
if( material2 == MAT_BIGGER && thismat > material1 ) setpoint = TRUE;
1679
if( material2 == MAT_SMALLER && thismat < material1 ) setpoint = TRUE;
1680
if( material2 == MAT_ANYTHING && thismat != material1 ) setpoint = TRUE;
1681
if( sidemat == material1 && thismat == material2 ) setpoint = TRUE;
1682
1683
if(setpoint == TRUE) {
1684
#if 0
1685
printf("going through boundary %d vs. %d in cell %d\n",material1,material2,no);
1686
#endif
1687
elem = 0;
1688
do {
1689
elem++;
1690
nosides++;
1691
more = GetSideInfo(cell,no,side,elem,elemind);
1692
1693
#if 0
1694
printf("elem=%d nosides=%d no=%d side=%d elemind=%d %d\n",
1695
elem,nosides, no, side, elemind[0], elemind[1]);
1696
#endif
1697
1698
/* In the second round the values are tabulated. */
1699
if(times) {
1700
/* It is assumed that the material pointed by solidmat
1701
determines the surface properties. */
1702
1703
bound->parent[nosides] = elemind[0];
1704
bound->parent2[nosides] = elemind[1];
1705
1706
bound->side[nosides] = side;
1707
bound->side2[nosides] = (side+dimsides/2)%dimsides;
1708
1709
bound->types[nosides] = boundarytype;
1710
1711
/* The direction of the surface normal must be included */
1712
if(solidmat==FIRST) {
1713
bound->material[nosides] = sidemat;
1714
bound->normal[nosides] = 1;
1715
}
1716
if(solidmat==SECOND){
1717
bound->material[nosides] = thismat;
1718
bound->normal[nosides] = -1;
1719
}
1720
}
1721
1722
1723
} while(more);
1724
}
1725
}
1726
1727
if(nosides == 0) {
1728
if(info) printf("No boundary between materials %d and %d exists.\n",
1729
material1,material2);
1730
return(0);
1731
}
1732
1733
if(times == 0) {
1734
times++;
1735
1736
/* Allocate space. This has sometimes led to strange errors.
1737
The allocation takes place only in the first loop. */
1738
1739
bound->created = TRUE;
1740
bound->nosides = size = nosides;
1741
bound->coordsystem = data->coordsystem;
1742
bound->types = Ivector(1,nosides);
1743
bound->side = Ivector(1,nosides);
1744
bound->side2 = Ivector(1,nosides);
1745
bound->material = Ivector(1,nosides);
1746
bound->parent = Ivector(1,nosides);
1747
bound->parent2 = Ivector(1,nosides);
1748
bound->normal = Ivector(1,nosides);
1749
1750
bound->echain = FALSE;
1751
bound->ediscont = FALSE;
1752
1753
goto startpoint;
1754
}
1755
1756
if(info) printf("%d element sides between materials %d and %d were located to type %d.\n",
1757
nosides,material1,material2,boundarytype);
1758
1759
return(0);
1760
}
1761
1762
1763
int AllocateBoundary(struct BoundaryType *bound,int size)
1764
{
1765
int i;
1766
1767
if(bound->created == TRUE) {
1768
printf("AllocateBoundary: You tried to recreate the boundary!\n");
1769
return(1);
1770
}
1771
1772
bound->created = TRUE;
1773
bound->nosides = size;
1774
bound->echain = FALSE;
1775
bound->ediscont = FALSE;
1776
1777
bound->material = Ivector(1,size);
1778
bound->side = Ivector(1,size);
1779
bound->side2 = Ivector(1,size);
1780
bound->parent = Ivector(1,size);
1781
bound->parent2 = Ivector(1,size);
1782
bound->types = Ivector(1,size);
1783
bound->normal = Ivector(1,size);
1784
1785
for(i=1;i<=size;i++) {
1786
bound->material[i] = 0;
1787
bound->side[i] = 0;
1788
bound->side2[i] = 0;
1789
bound->parent[i] = 0;
1790
bound->parent2[i] = 0;
1791
bound->types[i] = 0;
1792
bound->normal[i] = 1;
1793
}
1794
1795
return(0);
1796
}
1797
1798
1799
1800
int DestroyBoundary(struct BoundaryType *bound)
1801
/* Destroys boundaries of various types. */
1802
{
1803
int i,nosides;
1804
1805
if(!bound->created) {
1806
return(1);
1807
}
1808
nosides = bound->nosides;
1809
if(!nosides) {
1810
bound->created = FALSE;
1811
return(2);
1812
}
1813
1814
free_Ivector(bound->material,1,nosides);
1815
free_Ivector(bound->side,1,nosides);
1816
free_Ivector(bound->side2,1,nosides);
1817
free_Ivector(bound->parent,1,nosides);
1818
free_Ivector(bound->parent2,1,nosides);
1819
free_Ivector(bound->types,1,nosides);
1820
free_Ivector(bound->normal,1,nosides);
1821
1822
bound->nosides = 0;
1823
bound->created = FALSE;
1824
1825
#if DEBUG
1826
printf("%d element sides were destroyed.\n",nosides);
1827
#endif
1828
return(0);
1829
}
1830
1831
1832
1833
int CreatePoints(struct CellType *cell,struct FemType *data,
1834
struct BoundaryType *bound,
1835
int param1,int param2,int pointmode,int pointtype,int info)
1836
{
1837
int size,i,no,corner,times,elem,node;
1838
1839
bound->created = FALSE;
1840
bound->nosides = 0;
1841
times = 0;
1842
1843
omstart:
1844
i = 0;
1845
1846
/* Create nodes that are divided by the two materials specified */
1847
if(pointmode == 4) {
1848
for(no=1; no <= data->nocells; no++)
1849
if(cell[no].material == param2) {
1850
1851
for(corner=0; corner < 4; corner++)
1852
if(cell[no].boundary[4+corner] == param1) {
1853
1854
i++;
1855
1856
if(times) {
1857
bound->material[i] = param2;
1858
bound->types[i] = pointtype;
1859
bound->side[i] = 4 + corner;
1860
1861
if(corner == BOTLEFT)
1862
elem = GetElementIndex(&cell[no],1,1);
1863
else if(corner == BOTRIGHT)
1864
elem = GetElementIndex(&cell[no],cell[no].xelem,1);
1865
else if(corner == TOPRIGHT)
1866
elem = GetElementIndex(&cell[no],cell[no].xelem,cell[no].yelem);
1867
else if(corner == TOPLEFT)
1868
elem = GetElementIndex(&cell[no],1,cell[no].yelem);
1869
1870
bound->parent[i] = elem;
1871
}
1872
}
1873
}
1874
}
1875
1876
if(pointmode == 5) {
1877
corner = -1;
1878
for(no=1; no <= data->nocells && corner <0; no++) {
1879
if(cell[no].xind-1 == param1 && cell[no].yind-1 == param2)
1880
corner = BOTLEFT;
1881
else if(cell[no].xind == param1 && cell[no].yind-1 == param2)
1882
corner = BOTRIGHT;
1883
else if(cell[no].xind == param1 && cell[no].yind == param2)
1884
corner = TOPRIGHT;
1885
else if(cell[no].xind-1 == param1 && cell[no].yind == param2)
1886
corner = TOPLEFT;
1887
}
1888
if(corner >= 0) {
1889
i++;
1890
no--;
1891
}
1892
1893
if(times) {
1894
bound->types[i] = pointtype;
1895
bound->side[i] = 4 + corner;
1896
1897
if(corner == BOTLEFT)
1898
elem = GetElementIndex(&cell[no],1,1);
1899
else if(corner == BOTRIGHT)
1900
elem = GetElementIndex(&cell[no],cell[no].xelem,1);
1901
else if(corner == TOPRIGHT)
1902
elem = GetElementIndex(&cell[no],cell[no].xelem,cell[no].yelem);
1903
else if(corner == TOPLEFT)
1904
elem = GetElementIndex(&cell[no],1,cell[no].yelem);
1905
1906
bound->parent[i] = elem;
1907
node = data->topology[elem][corner];
1908
if(info) printf("Found node %d at (%.3lg, %.3lg)\n",node,data->x[node],data->y[node]);
1909
}
1910
}
1911
1912
size = i;
1913
if(times == 0 && size > 0) {
1914
AllocateBoundary(bound,size);
1915
times = 1;
1916
goto omstart;
1917
}
1918
1919
if(info) printf("Created %d new points of type %d in the corner of materials %d and %d.\n",
1920
size,pointtype,param1,param2);
1921
1922
return(FALSE);
1923
}
1924
1925
1926
1927
int CreateNewNodes(struct FemType *data,int *order,int material,int newknots)
1928
{
1929
int i,j,k,l,lmax,ind;
1930
int newsize,noknots,nonodes;
1931
int *neworder;
1932
Real *newx=NULL,*newy=NULL,*newz=NULL;
1933
Real *newdofs[MAXDOFS];
1934
1935
noknots = data->noknots;
1936
1937
printf("Creating %d new nodes for discontinuous boundary.\n",newknots);
1938
1939
/* Allocate for the new nodes */
1940
newsize = noknots+newknots;
1941
newx = Rvector(1,newsize);
1942
newy = Rvector(1,newsize);
1943
newz = Rvector(1,newsize);
1944
1945
neworder = Ivector(1,newsize);
1946
1947
for(j=1;j<MAXDOFS;j++)
1948
if(data->edofs[j])
1949
newdofs[j] = Rvector(1,data->edofs[j]*newsize);
1950
1951
/* Set the new coordinates and dofs */
1952
j = 0;
1953
for(i=1;i<=noknots;i++) {
1954
j++;
1955
neworder[j] = i;
1956
newx[j] = data->x[i];
1957
newy[j] = data->y[i];
1958
newz[j] = data->z[i];
1959
1960
for(k=1;k<MAXDOFS;k++) {
1961
if((lmax = data->edofs[k]))
1962
for(l=1;l<=lmax;l++)
1963
newdofs[k][lmax*(j-1)+l] = data->dofs[k][lmax*(i-1)+l];
1964
}
1965
1966
if(order[i] < 0) {
1967
j++;
1968
neworder[j] = -i;
1969
newx[j] = data->x[i];
1970
newy[j] = data->y[i];
1971
newz[j] = data->z[i];
1972
1973
for(k=1;k<MAXDOFS;k++) {
1974
if((lmax = data->edofs[k]))
1975
for(l=1;l<=lmax;l++)
1976
newdofs[k][lmax*(j-1)+l] = data->dofs[k][lmax*(i-1)+l];
1977
}
1978
}
1979
}
1980
1981
/* Find the old index corresponding to the new one. */
1982
for(i=1;i<=newsize;i++)
1983
if(neworder[i] > 0) {
1984
if(order[neworder[i]] < 0)
1985
order[neworder[i]] = -i;
1986
else
1987
order[neworder[i]] = i;
1988
}
1989
1990
/* Set the new element topology */
1991
for(i=1;i<=data->noelements;i++) {
1992
nonodes = data->elementtypes[i]%100;
1993
for(j=0;j<nonodes;j++) {
1994
ind = data->topology[i][j];
1995
if(data->material[i] == material && order[ind] < 0)
1996
data->topology[i][j] = abs(order[ind])+1;
1997
else
1998
data->topology[i][j] = abs(order[ind]);
1999
}
2000
}
2001
2002
/* Destroy old vectors and set the pointers to the new vectors. */
2003
free_Rvector(data->x,1,noknots);
2004
free_Rvector(data->y,1,noknots);
2005
free_Rvector(data->z,1,noknots);
2006
2007
for(k=1;k<MAXDOFS;k++)
2008
if(data->edofs[k]) free_Rvector(data->dofs[k],1,noknots);
2009
2010
data->noknots = newsize;
2011
data->x = newx;
2012
data->y = newy;
2013
data->z = newz;
2014
2015
for(k=1;k<MAXDOFS;k++) {
2016
if(data->edofs[k]) {
2017
data->dofs[k] = newdofs[k];
2018
data->alldofs[k] = data->edofs[k] * data->noknots;
2019
}
2020
}
2021
2022
return(0);
2023
}
2024
2025
2026
int SetDiscontinuousBoundary(struct FemType *data,struct BoundaryType *bound,
2027
int boundtype,int endnodes,int info)
2028
/* Create secondary points for a given boundary.
2029
This feature is handy when one wants to solve problems with discontinuous
2030
field variables.
2031
*/
2032
{
2033
int i,j,bc,ind,sideind[MAXNODESD1];
2034
int side,parent,newnodes,doublesides,maxtype,newbc;
2035
int newsuccess,noelements,nonodes,sideelemtype,sidenodes,disconttype;
2036
int *order=NULL;
2037
int mat1,mat2,par1,par2,mat1old,mat2old,material;
2038
static int hitsexist=FALSE,hitslength,*hits=NULL;
2039
2040
2041
if(boundtype < 0) {
2042
newbc = TRUE;
2043
boundtype = -boundtype;
2044
}
2045
else {
2046
newbc = FALSE;
2047
}
2048
2049
mat1old = mat2old = 0;
2050
doublesides = 0;
2051
2052
/* Compute the number of duplicate boundary elements */
2053
for(bc=0;bc<MAXBOUNDARIES;bc++) {
2054
2055
if(bound[bc].created == FALSE) continue;
2056
if(!bound->nosides) continue;
2057
2058
for(i=1;i<=bound[bc].nosides;i++) {
2059
if(bound[bc].types[i] == boundtype) {
2060
par1 = bound[bc].parent[i];
2061
par2 = bound[bc].parent2[i];
2062
if(par1 && par2) {
2063
doublesides++;
2064
mat1 = data->material[par1];
2065
mat2 = data->material[par2];
2066
if(!mat1old) mat1old = mat1;
2067
else if(mat1old != mat1) mat1old = -mat1;
2068
if(!mat2old) mat2old = mat2;
2069
else if(mat2old != mat2) mat2old = -mat2;
2070
}
2071
}
2072
}
2073
}
2074
2075
if(!doublesides) return(1);
2076
2077
if( mat1old > 0 && mat2old > 0 )
2078
material = MIN( mat1old, mat2old );
2079
else if(mat1old > 0)
2080
material = mat1old;
2081
else if(mat2old > 0)
2082
material = mat2old;
2083
else {
2084
printf("SetDiscontinuousBoundary: impossible to make the boundary of several materials\n");
2085
return(2);
2086
}
2087
2088
if(info) {
2089
printf("Creating discontinuous boundary between materials %d and %d\n",mat1old,mat2old);
2090
printf("New set of nodes will be created for material %d\n",material);
2091
}
2092
2093
2094
noelements = data->noelements;
2095
order = Ivector(1,data->noknots);
2096
for(i=1;i<=data->noknots;i++)
2097
order[i] = i;
2098
2099
/* Compute the endnodes by the fact that they have different number of
2100
hits */
2101
if(endnodes == 1) {
2102
if(!hitsexist) {
2103
hitslength = 1.1*data->noknots;
2104
hits = Ivector(1,hitslength);
2105
hitsexist = TRUE;
2106
}
2107
else if(hitslength <= data->noknots) {
2108
free_Ivector(hits,1,hitslength);
2109
hitslength = 1.1*data->noknots;
2110
hits = Ivector(1,hitslength);
2111
}
2112
2113
for(i=1;i<=data->noknots;i++)
2114
hits[i] = 0;
2115
2116
for(j=1;j<=noelements;j++) {
2117
nonodes = data->elementtypes[j]%100;
2118
for(i=0;i<nonodes;i++)
2119
hits[data->topology[j][i]] += 1;
2120
}
2121
}
2122
2123
/* If requested create a secondary boundary at the other side */
2124
if(newbc) {
2125
maxtype = 0;
2126
for(bc=0;bc<MAXBOUNDARIES;bc++) {
2127
for(i=1;i<=bound[bc].nosides;i++) {
2128
maxtype = MAX(maxtype, bound[bc].types[i]);
2129
if(bound[bc].ediscont) maxtype = MAX(maxtype, bound[bc].discont[i]);
2130
}
2131
}
2132
disconttype = maxtype + 1;
2133
if(info) printf("Type of the other side of discontinuous boundary set to %d.\n",disconttype);
2134
}
2135
else {
2136
disconttype = boundtype;
2137
}
2138
2139
2140
2141
/* Find the number of new nodes */
2142
newnodes = 0;
2143
2144
for(bc=0;bc<MAXBOUNDARIES;bc++) {
2145
2146
for(i=1;i<=bound[bc].nosides;i++) {
2147
2148
if(bound[bc].types[i] != boundtype) continue;
2149
2150
if(!bound[bc].ediscont) {
2151
bound[bc].discont = Ivector(1,bound[bc].nosides);
2152
for(j=1;j<=bound[bc].nosides;j++)
2153
bound[bc].discont[j] = 0;
2154
bound[bc].ediscont = TRUE;
2155
}
2156
2157
parent = bound[bc].parent2[i];
2158
if(parent == 0) continue;
2159
side = bound[bc].side2[i];
2160
GetElementSide(parent,side,1,data,sideind,&sideelemtype);
2161
sidenodes = sideelemtype%100;
2162
2163
bound[bc].discont[i] = disconttype;
2164
2165
for(j=0;j<sidenodes;j++) {
2166
ind = abs(sideind[j]);
2167
2168
if(endnodes == 2) {
2169
if(order[ind] > 0) {
2170
newnodes++;
2171
order[ind] = -newnodes;
2172
}
2173
}
2174
else if(endnodes == 0) {
2175
if(order[ind] > 0)
2176
order[ind] = 0;
2177
else if(order[ind] == 0) {
2178
newnodes++;
2179
order[ind] = -newnodes;
2180
}
2181
}
2182
else if(endnodes == 1) {
2183
if(order[ind] > 0) {
2184
if(hits[ind] < 4) {
2185
newnodes++;
2186
order[ind] = -newnodes;
2187
}
2188
else
2189
order[ind] = 0;
2190
}
2191
else if(order[ind] == 0) {
2192
newnodes++;
2193
order[ind] = -newnodes;
2194
}
2195
}
2196
2197
}
2198
}
2199
2200
if(endnodes == 0 || endnodes == 1) {
2201
for(i=1;i<=data->noknots;i++)
2202
if(order[i] == 0)
2203
order[i] = i;
2204
}
2205
}
2206
2207
if(newnodes == 0) return(3);
2208
2209
newsuccess = CreateNewNodes(data,order,material,newnodes);
2210
return(newsuccess);
2211
}
2212
2213
2214
2215
int FindPeriodicBoundary(struct FemType *data,struct BoundaryType *bound,
2216
int boundary1,int boundary2,int info)
2217
/* Create periodic boundary conditions for a given boundary pair
2218
boundary1, boundary2.
2219
*/
2220
{
2221
int i,j,k,l;
2222
int parent,elemtype;
2223
int minp[2],maxp[2],bounds[2],dp[2],sumsides[2];
2224
2225
if(bound->created == FALSE) {
2226
printf("SetDiscontinuousBoundary: The boundary does not exist!\n");
2227
return(1);
2228
}
2229
if(!bound->nosides) return(0);
2230
2231
2232
bounds[0] = boundary1;
2233
bounds[1] = boundary2;
2234
minp[0] = minp[1] = data->noknots+1;
2235
maxp[0] = maxp[1] = 0;
2236
2237
sumsides[0] = sumsides[1] = 0;
2238
for(j=0;j < MAXBOUNDARIES;j++) {
2239
if(bound->created == FALSE) continue;
2240
2241
for(i=1; i <= bound[j].nosides; i++) {
2242
2243
for(k=0;k<=1;k++) {
2244
if(bound[j].types[i] == bounds[k]) {
2245
2246
sumsides[k] += 1;
2247
if(bound[j].parent[i] > maxp[k]) maxp[k] = bound[j].parent[i];
2248
if(bound[j].parent[i] < minp[k]) minp[k] = bound[j].parent[i];
2249
}
2250
}
2251
}
2252
}
2253
2254
for (k=0;k<=1;k++) {
2255
dp[k] = maxp[k] - minp[k];
2256
if(info) printf("Parents of boundary %d are on the interval [%d, %d]\n",
2257
bounds[k],minp[k],maxp[k]);
2258
}
2259
2260
if(dp[0] != dp[1] || sumsides[0] != sumsides[1]) {
2261
printf("FindPeriodicBoundary: The simple scheme cannot handle these boundaries!\n");
2262
printf("dp=[%d %d] sumsides=[%d %d]\n",dp[0],dp[1],sumsides[0],sumsides[1]);
2263
return(1);
2264
}
2265
2266
for(j=0;j < MAXBOUNDARIES;j++) {
2267
if(bound->created == FALSE) continue;
2268
2269
for(i=1; i <= bound[j].nosides; i++) {
2270
2271
for(k=0;k<=1;k++) {
2272
if(bound[j].types[i] == bounds[k]) {
2273
parent = bound[j].parent[i];
2274
bound[j].parent2[i] = bound[j].parent[i] - minp[k] + minp[(k+1)%2];
2275
2276
if(!bound[j].ediscont) {
2277
bound[j].discont = Ivector(1,bound[j].nosides);
2278
for(l=1; l <= bound[j].nosides; l++)
2279
bound[j].discont[l] = 0;
2280
bound[j].ediscont = TRUE;
2281
}
2282
2283
bound[j].discont[i] = 2+k;
2284
elemtype = data->elementtypes[parent];
2285
if(elemtype%100 == 4) {
2286
bound[j].side2[i] = (bound[j].side[i] + 2) % 4;
2287
}
2288
else if(elemtype%100 == 8) {
2289
if(bound[j].side[i] < 4) bound[j].side2[i] = (bound[j].side[i] + 2) % 4;
2290
if(bound[j].side[i] >= 4) bound[j].side2[i] = 4 + (5 - bound[j].side[i]);
2291
}
2292
}
2293
}
2294
}
2295
}
2296
2297
if(info) printf("Periodic boundaries were set with a simple scheme\n");
2298
2299
return(2);
2300
}
2301
2302
2303
2304
int SetConnectedNodes(struct FemType *data,struct BoundaryType *bound,
2305
int bctype,int connecttype,int info)
2306
/* Mark node that are related to a boundary condition of a given bctype.
2307
This may be used to create strong connections in the partitioning process. */
2308
{
2309
int i,j,k,bc,sideelemtype,sidenodes,nodesset;
2310
int sideind[MAXNODESD1],conflicts;
2311
2312
conflicts = 0;
2313
nodesset = 0;
2314
2315
for(bc=0;bc<MAXBOUNDARIES;bc++) {
2316
if(bound[bc].created == FALSE) continue;
2317
if(bound[bc].nosides == 0) continue;
2318
2319
for(i=1;i<=bound[bc].nosides;i++) {
2320
if( bctype > 0 ) {
2321
if(bound[bc].types[i] != bctype) continue;
2322
}
2323
else if( bctype == -1 ) {
2324
if( !bound[bc].parent[i] ) continue;
2325
}
2326
else if( bctype == -2 ) {
2327
if( !bound[bc].parent[i] ) continue;
2328
if( !bound[bc].parent2[i] ) continue;
2329
}
2330
else if( bctype == -3 ) {
2331
if( !bound[bc].parent[i] ) continue;
2332
if( bound[bc].parent2[i] ) continue;
2333
}
2334
2335
/* If the table pointing the connected nodes does not exist, create it */
2336
if(!data->nodeconnectexist) {
2337
data->nodeconnect = Ivector(1,data->noknots);
2338
for(k=1;k<=data->noknots;k++)
2339
data->nodeconnect[k] = 0;
2340
data->nodeconnectexist = TRUE;
2341
}
2342
2343
GetElementSide(bound[bc].parent[i],bound[bc].side[i],bound[bc].normal[i],
2344
data,sideind,&sideelemtype);
2345
sidenodes = sideelemtype%100;
2346
2347
for(j=0;j<sidenodes;j++) {
2348
k = sideind[j];
2349
if( data->nodeconnect[k] != connecttype ) {
2350
if( data->nodeconnect[k] ) conflicts += 1;
2351
data->nodeconnect[k] = connecttype;
2352
nodesset += 1;
2353
}
2354
}
2355
}
2356
}
2357
if(info) printf("Setting connectivity group %d for %d nodes on boundary %d\n",
2358
connecttype,nodesset,bctype);
2359
2360
if(conflicts) printf("The were %d conflicts in the connectivity set %d\n",
2361
conflicts,connecttype);
2362
2363
return(0);
2364
}
2365
2366
2367
int SetConnectedElements(struct FemType *data,int info)
2368
/* Create connected boundary conditions for a given bctype */
2369
{
2370
int i,j,k,nonodes,hit,nohits,con;
2371
int *nodeconnect;
2372
2373
if(!data->nodeconnectexist) {
2374
printf("Cannot create connected elements without connected nodes!\n");
2375
return(1);
2376
}
2377
nodeconnect = data->nodeconnect;
2378
2379
/* Allocated space for the connected elements */
2380
if(!data->elemconnectexist) {
2381
printf("Created table for connected elements\n");
2382
data->elemconnect = Ivector(1,data->noelements);
2383
for(k=1;k<=data->noelements;k++)
2384
data->elemconnect[k] = 0;
2385
data->elemconnectexist = TRUE;
2386
2387
/* Go through all the elements and check which of the elements have
2388
nodes that are related to a connected node */
2389
nohits = 0;
2390
for(i=1;i<=data->noelements;i++) {
2391
nonodes = data->elementtypes[i] % 100;
2392
hit = FALSE;
2393
for(j=0;j<nonodes;j++) {
2394
k = data->topology[i][j];
2395
con = nodeconnect[k];
2396
if( con ) {
2397
data->elemconnect[i] = MAX( con, data->elemconnect[i] );
2398
hit = TRUE;
2399
}
2400
}
2401
if(hit) nohits++;
2402
}
2403
2404
if(info) printf("Number of connected elements is %d (out of %d)\n",nohits,data->noelements);
2405
data->elemconnectexist = nohits;
2406
}
2407
2408
/* This is a little bit dirty. We set the connections to negative and use the unconnected
2409
as a permutation. */
2410
if( data->elemconnectexist ) {
2411
if(info) printf("Use connected table as a permutation for creating dual graph!\n");
2412
j = 0;
2413
for(i=1;i<=data->noelements;i++) {
2414
if( data->elemconnect[i] ) {
2415
data->elemconnect[i] = -abs(data->elemconnect[i]);
2416
}
2417
else {
2418
j++;
2419
data->elemconnect[i] = j;
2420
}
2421
}
2422
}
2423
2424
return(0);
2425
}
2426
2427
2428
2429
int FindCorners(struct GridType *grid,struct CellType *cell,
2430
struct FemType *data,int info)
2431
/* Find the nodes in the mesh that are at material corners.
2432
These nodes are often of special interest.
2433
*/
2434
{
2435
int i,j,k,ind,cellno,elem;
2436
int allocated,nocorners;
2437
2438
nocorners = 0;
2439
allocated = FALSE;
2440
2441
omstart:
2442
2443
if(nocorners > 0) {
2444
data->corners = Ivector(1,2*nocorners);
2445
data->nocorners = nocorners;
2446
allocated = TRUE;
2447
}
2448
2449
k = 0;
2450
2451
for(i=1;i<=grid->xcells+1;i++)
2452
for(j=1;j<=grid->ycells+1;j++) {
2453
if(grid->structure[j][i] == grid->structure[j][i-1] &&
2454
grid->structure[j-1][i] == grid->structure[j-1][i-1])
2455
continue;
2456
if(grid->structure[j][i] == grid->structure[j-1][i] &&
2457
grid->structure[j][i-1] == grid->structure[j-1][i-1])
2458
continue;
2459
2460
/* point (i,j) must now be a corner */
2461
if((cellno = grid->numbered[j][i])) {
2462
elem = GetElementIndex(&(cell)[cellno],1,1);
2463
ind = BOTLEFT;
2464
}
2465
else if((cellno = grid->numbered[j][i-1])) {
2466
elem = GetElementIndex(&(cell)[cellno],cell[cellno].xelem,1);
2467
ind = BOTRIGHT;
2468
}
2469
else if((cellno = grid->numbered[j-1][i])) {
2470
elem = GetElementIndex(&(cell)[cellno],1,cell[cellno].yelem);
2471
ind = TOPLEFT;
2472
}
2473
else if((cellno = grid->numbered[j-1][i-1])) {
2474
elem = GetElementIndex(&(cell)[cellno],cell[cellno].xelem,cell[cellno].yelem);
2475
ind = TOPRIGHT;
2476
}
2477
else continue;
2478
2479
/* ind is now the index of the corner knot */
2480
k++;
2481
2482
if(allocated == FALSE) continue;
2483
data->corners[2*k-1] = elem;
2484
data->corners[2*k] = ind;
2485
2486
}
2487
2488
nocorners = k;
2489
2490
if(nocorners == 0) return(0);
2491
if(allocated == FALSE) goto omstart;
2492
2493
if(info) printf("Found %d material corners.\n",nocorners);
2494
return(0);
2495
}
2496
2497
2498
2499
int ElementsToTriangles(struct FemType *data,struct BoundaryType *bound,
2500
Real critangle,int info)
2501
/* Make triangles out of rectangular elements */
2502
{
2503
int i,j,k,l,side,elem,i1,isum,sideelemtype;
2504
int noelements,elementtype,triangles,noknots,nonodes,newelements,newtype,newmaxnodes;
2505
int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL;
2506
int newnodes,*needed=NULL,*divisions=NULL,*division1=NULL;
2507
int sideind[MAXNODESD1], sideind2[MAXNODESD1];
2508
int allocated,maxanglej,evenodd,newelem;
2509
Real dx1,dx2,dy1,dy2,ds1,ds2;
2510
Real angles[4],maxangle;
2511
struct FemType data2;
2512
2513
noelements = data->noelements;
2514
noknots = data->noknots;
2515
allocated = FALSE;
2516
2517
needed = Ivector(1,noknots);
2518
for(i=1;i<=noknots;i++)
2519
needed[i] = 0;
2520
for(i=1;i<=noelements;i++) {
2521
nonodes = data->elementtypes[i] / 100;
2522
for(j=0;j<nonodes;j++)
2523
needed[data->topology[i][j]] += 1;
2524
}
2525
2526
divisions = Ivector(1,noelements);
2527
division1 = Ivector(1,noelements);
2528
for(i=1;i<=noelements;i++)
2529
divisions[i] = division1[i] = 0;
2530
2531
/* First divide the elements along the shorter diameter */
2532
2533
newelements = 0;
2534
newmaxnodes = 0;
2535
2536
omstart:
2537
2538
for(i=1;i<=noelements;i++) {
2539
2540
elementtype = data->elementtypes[i];
2541
2542
/* compute the four angles and divide the rectangle so that the largest angle is split */
2543
maxangle = 0.0;
2544
maxanglej = 0;
2545
for(j=0;j<4;j++) {
2546
dx1 = data->x[data->topology[i][(j+3)%4]] - data->x[data->topology[i][j]];
2547
dy1 = data->y[data->topology[i][(j+3)%4]] - data->y[data->topology[i][j]];
2548
dx2 = data->x[data->topology[i][(j+1)%4]] - data->x[data->topology[i][j]];
2549
dy2 = data->y[data->topology[i][(j+1)%4]] - data->y[data->topology[i][j]];
2550
ds1 = sqrt(dx1*dx1+dy1*dy1);
2551
ds2 = sqrt(dx2*dx2+dy2*dy2);
2552
angles[j] = (180.0/FM_PI) * acos((dx1*dx2+dy1*dy2)/(ds1*ds2));
2553
2554
/* Slightly favor divisions where corner is split */
2555
if(needed[data->topology[i][j]] == 1) angles[j] *= 1.001;
2556
2557
if( abs(angles[j] > maxangle)) {
2558
maxangle = abs(angles[j]);
2559
maxanglej = j;
2560
}
2561
}
2562
evenodd = maxanglej % 2;
2563
2564
2565
/* No triangularization is performed unless the critical angle is exceeded. */
2566
if( maxangle < critangle ) {
2567
triangles = 1;
2568
newtype = elementtype;
2569
newnodes = elementtype % 100;
2570
}
2571
else {
2572
switch(elementtype) {
2573
case 404:
2574
newtype = 303;
2575
newnodes = 3;
2576
triangles = 2;
2577
break;
2578
case 405:
2579
newtype = 303;
2580
newnodes = 3;
2581
triangles = 4;
2582
break;
2583
case 409:
2584
newtype = 306;
2585
newnodes = 6;
2586
triangles = 2;
2587
break;
2588
case 416:
2589
newtype = 310;
2590
newnodes = 10;
2591
triangles = 2;
2592
break;
2593
default:
2594
printf("ElementsToTriangles: not implemented for elementtype %d\n",elementtype);
2595
return(1);
2596
}
2597
}
2598
2599
newmaxnodes = MAX( newnodes, newmaxnodes );
2600
2601
2602
if(!allocated) {
2603
divisions[i] = triangles;
2604
division1[i] = newelements;
2605
newelements += triangles;
2606
continue;
2607
}
2608
2609
for(j=division1[i]+1;j<=division1[i]+divisions[i];j++) {
2610
newelementtypes[j] = newtype;
2611
newmaterial[j] = data->material[i];
2612
}
2613
2614
newelem = division1[i]+1;
2615
if(triangles == 1) {
2616
for(j=0;j<newnodes;j++)
2617
newtopo[newelem][j] = data->topology[i][j];
2618
}
2619
else {
2620
if(elementtype == 404 || elementtype == 409 || elementtype == 416) {
2621
if(evenodd) {
2622
newtopo[newelem][0] = data->topology[i][0];
2623
newtopo[newelem][1] = data->topology[i][1];
2624
newtopo[newelem][2] = data->topology[i][3];
2625
newtopo[newelem+1][0] = data->topology[i][2];
2626
newtopo[newelem+1][1] = data->topology[i][3];
2627
newtopo[newelem+1][2] = data->topology[i][1];
2628
}
2629
else {
2630
newtopo[newelem][0] = data->topology[i][1];
2631
newtopo[newelem][1] = data->topology[i][2];
2632
newtopo[newelem][2] = data->topology[i][0];
2633
newtopo[newelem+1][0] = data->topology[i][3];
2634
newtopo[newelem+1][1] = data->topology[i][0];
2635
newtopo[newelem+1][2] = data->topology[i][2];
2636
}
2637
}
2638
if(elementtype == 409) {
2639
if(evenodd) {
2640
newtopo[newelem][3] = data->topology[i][4];
2641
newtopo[newelem][4] = data->topology[i][8];
2642
newtopo[newelem][5] = data->topology[i][7];
2643
newtopo[newelem+1][3] = data->topology[i][6];
2644
newtopo[newelem+1][4] = data->topology[i][8];
2645
newtopo[newelem+1][5] = data->topology[i][5];
2646
}
2647
else {
2648
newtopo[newelem][3] = data->topology[i][5];
2649
newtopo[newelem][4] = data->topology[i][8];
2650
newtopo[newelem][5] = data->topology[i][4];
2651
newtopo[newelem+1][3] = data->topology[i][7];
2652
newtopo[newelem+1][4] = data->topology[i][8];
2653
newtopo[newelem+1][5] = data->topology[i][6];
2654
}
2655
}
2656
if(elementtype == 416) {
2657
if(evenodd) {
2658
newtopo[newelem][3] = data->topology[i][4];
2659
newtopo[newelem][4] = data->topology[i][5];
2660
newtopo[newelem][5] = data->topology[i][13];
2661
newtopo[newelem][6] = data->topology[i][15];
2662
newtopo[newelem][7] = data->topology[i][10];
2663
newtopo[newelem][8] = data->topology[i][11];
2664
newtopo[newelem][9] = data->topology[i][12];
2665
2666
newtopo[newelem+1][3] = data->topology[i][8];
2667
newtopo[newelem+1][4] = data->topology[i][9];
2668
newtopo[newelem+1][5] = data->topology[i][15];
2669
newtopo[newelem+1][6] = data->topology[i][13];
2670
newtopo[newelem+1][7] = data->topology[i][6];
2671
newtopo[newelem+1][8] = data->topology[i][7];
2672
newtopo[newelem+1][9] = data->topology[i][14];
2673
}
2674
else {
2675
newtopo[newelem][3] = data->topology[i][6];
2676
newtopo[newelem][4] = data->topology[i][7];
2677
newtopo[newelem][5] = data->topology[i][14];
2678
newtopo[newelem][6] = data->topology[i][12];
2679
newtopo[newelem][7] = data->topology[i][4];
2680
newtopo[newelem][8] = data->topology[i][5];
2681
newtopo[newelem][9] = data->topology[i][13];
2682
2683
newtopo[newelem+1][3] = data->topology[i][10];
2684
newtopo[newelem+1][4] = data->topology[i][11];
2685
newtopo[newelem+1][5] = data->topology[i][12];
2686
newtopo[newelem+1][6] = data->topology[i][14];
2687
newtopo[newelem+1][7] = data->topology[i][8];
2688
newtopo[newelem+1][8] = data->topology[i][9];
2689
newtopo[newelem+1][9] = data->topology[i][15];
2690
}
2691
}
2692
else if(elementtype == 405) {
2693
newtopo[newelem][0] = data->topology[i][0];
2694
newtopo[newelem][1] = data->topology[i][1];
2695
newtopo[newelem][2] = data->topology[i][4];
2696
newtopo[newelem+1][0] = data->topology[i][1];
2697
newtopo[newelem+1][1] = data->topology[i][2];
2698
newtopo[newelem+1][2] = data->topology[i][4];
2699
newtopo[newelem+2][0] = data->topology[i][2];
2700
newtopo[newelem+2][1] = data->topology[i][3];
2701
newtopo[newelem+2][2] = data->topology[i][4];
2702
newtopo[newelem+3][0] = data->topology[i][3];
2703
newtopo[newelem+3][1] = data->topology[i][0];
2704
newtopo[newelem+3][2] = data->topology[i][4];
2705
}
2706
}
2707
}
2708
2709
2710
if(!allocated) {
2711
2712
newtopo = Imatrix(1,newelements,0,newmaxnodes-1);
2713
newmaterial = Ivector(1,newelements);
2714
newelementtypes = Ivector(1,newelements);
2715
allocated = TRUE;
2716
2717
data2 = *data;
2718
data2.topology = newtopo;
2719
data2.material = newmaterial;
2720
data2.elementtypes = newelementtypes;
2721
2722
goto omstart;
2723
}
2724
2725
2726
/* Then make the corresponding mapping for the BCs.
2727
This is done in a brute-force way where all the
2728
possible new elements are checked. */
2729
2730
for(j=0;j < MAXBOUNDARIES;j++) {
2731
if(!bound[j].created) continue;
2732
2733
for(i=1; i <= bound[j].nosides; i++) {
2734
2735
for(l=1;l<=2;l++) {
2736
2737
if(l==1)
2738
k = bound[j].parent[i];
2739
else
2740
k = bound[j].parent2[i];
2741
if(k == 0) continue;
2742
2743
2744
if(l == 1)
2745
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
2746
data,sideind,&sideelemtype);
2747
else
2748
GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],
2749
data,sideind,&sideelemtype);
2750
2751
if(sideelemtype/100 != 2) {
2752
printf("ElementsToTriangles: implemented only for BCs 202 and 203\n");
2753
continue;
2754
}
2755
2756
isum = 0;
2757
side = 0;
2758
if(divisions[k] == 1) {
2759
elem = division1[k]+1;
2760
side = bound[j].side[i];
2761
isum = 2;
2762
goto nextparent;
2763
}
2764
2765
/* Test for all possible elements that could be parents */
2766
for(elem=division1[k]+1;elem<=division1[k]+divisions[k];elem++) {
2767
isum = 0;
2768
for(i1=0;i1<3;i1++) {
2769
if(newtopo[elem][i1] == sideind[0]) isum++;
2770
if(newtopo[elem][i1] == sideind[1]) isum++;
2771
}
2772
2773
if(isum != 2) continue;
2774
2775
for(side=0;side<3;side++) {
2776
GetElementSide(elem,side,bound[j].normal[i],
2777
&data2,sideind2,&sideelemtype);
2778
isum = 0;
2779
for(i1=0;i1<2;i1++) {
2780
if(sideind2[i1] == sideind[0]) isum++;
2781
if(sideind2[i1] == sideind[1]) isum++;
2782
}
2783
2784
if(isum == 2) goto nextparent;
2785
}
2786
}
2787
2788
nextparent:
2789
if(isum == 2) {
2790
if(l == 1) {
2791
bound[j].parent[i] = elem;
2792
bound[j].side[i] = side;
2793
}
2794
if(l == 2) {
2795
bound[j].parent2[i] = elem;
2796
bound[j].side2[i] = side;
2797
}
2798
}
2799
else {
2800
printf("Failed to find parent for side %d of %d (parent %d)\n",i,j,k);
2801
}
2802
}
2803
}
2804
}
2805
2806
2807
free_Imatrix(data->topology,1,noelements,0,data->maxnodes-1);
2808
free_Ivector(data->material,1,noelements);
2809
free_Ivector(data->elementtypes,1,noelements);
2810
free_Ivector(needed,1,noknots);
2811
free_Ivector(divisions,1,noelements);
2812
free_Ivector(division1,1,noelements);
2813
2814
data->topology = newtopo;
2815
data->elementtypes = newelementtypes;
2816
data->material = newmaterial;
2817
data->noelements = newelements;
2818
data->maxnodes = newmaxnodes;
2819
2820
if(info) printf("There are %d elements after triangularization (was %d)\n",
2821
newelements,noelements);
2822
2823
return(0);
2824
}
2825
2826
2827
int PolarCoordinates(struct FemType *data,Real rad,int info)
2828
{
2829
int i;
2830
Real fii,zet,dr;
2831
2832
for(i=1;i<=data->noknots;i++) {
2833
zet = data->x[i];
2834
fii = FM_PI/180.0 * data->y[i];
2835
dr = data->z[i];
2836
2837
data->z[i] = zet;
2838
data->x[i] = (rad+dr) * cos(fii);
2839
data->y[i] = (rad+dr) * sin(fii);
2840
}
2841
2842
if(info) printf("Making coordinate transformation from polar to cartesian\n");
2843
2844
return(0);
2845
}
2846
2847
2848
int CylinderCoordinates(struct FemType *data,int info)
2849
{
2850
int i;
2851
Real x,y,z,rad,fii;
2852
2853
if( data->dim == 3 ) {
2854
for(i=1;i<=data->noknots;i++) {
2855
x = data->x[i];
2856
y = data->y[i];
2857
fii = FM_PI/180.0 * data->z[i];
2858
rad = data->x[i];
2859
2860
data->x[i] = rad * cos(fii);
2861
data->y[i] = rad * sin(fii);
2862
data->z[i] = y;
2863
}
2864
}
2865
else {
2866
for(i=1;i<=data->noknots;i++) {
2867
rad = data->x[i];
2868
fii = FM_PI/180.0 * data->y[i];
2869
2870
data->x[i] = rad * cos(fii);
2871
data->y[i] = rad * sin(fii);
2872
}
2873
}
2874
2875
if(info) printf("Making coordinate transformation from cylindrical to cartesian\n");
2876
2877
return(0);
2878
}
2879
2880
2881
int UniteMeshes(struct FemType *data1,struct FemType *data2,
2882
struct BoundaryType *bound1,struct BoundaryType *bound2,
2883
int nooverlap, int info)
2884
/* Unites two meshes for one larger mesh */
2885
{
2886
int i,j,k;
2887
int noelements,noknots,nonodes,maxnodes;
2888
int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL;
2889
Real *newx=NULL,*newy=NULL,*newz=NULL;
2890
int mat,usenames,*bodynameis,*boundarynameis,*bodyused,*boundaryused;
2891
int bcmax1,bcmin2,bcoffset;
2892
int bodymax1,bodymin2,bodyoffset;
2893
2894
noknots = data1->noknots + data2->noknots;
2895
noelements = data1->noelements + data2->noelements;
2896
maxnodes = MAX(data1->maxnodes,data2->maxnodes);
2897
2898
if(data2->dim > data1->dim) data1->dim = data2->dim;
2899
2900
if(0) printf("Uniting two meshes to %d nodes and %d elements.\n",noknots,noelements);
2901
2902
usenames = data1->bodynamesexist || data1->boundarynamesexist;
2903
bcoffset = 0; bodyoffset = 0;
2904
2905
if( usenames ) {
2906
bodynameis = Ivector(1,MAXBODIES);
2907
boundarynameis = Ivector(1,MAXBCS);
2908
bodyused = Ivector(1,MAXBODIES);
2909
boundaryused = Ivector(1,MAXBCS);
2910
2911
for(i=1;i<=MAXBODIES;i++)
2912
bodynameis[i] = bodyused[i] = FALSE;
2913
for(i=1;i<=MAXBCS;i++)
2914
boundarynameis[i] = boundaryused[i] = FALSE;
2915
2916
/* First mark the original bodies and boundaries that maintain their index */
2917
for(i=1;i<=data1->noelements;i++) {
2918
mat = data1->material[i];
2919
if( mat < MAXBODIES ) {
2920
if(!bodynameis[mat]) {
2921
bodynameis[mat] = -1;
2922
bodyused[mat] = TRUE;
2923
}
2924
}
2925
}
2926
2927
for(j=0;j < MAXBOUNDARIES;j++) {
2928
if(!bound1[j].created) continue;
2929
for(i=1; i <= bound1[k].nosides; i++) {
2930
mat = bound1[j].types[i];
2931
if( mat < MAXBCS ) {
2932
if(!boundarynameis[mat]) {
2933
boundarynameis[mat] = -1;
2934
boundaryused[mat] = TRUE;
2935
}
2936
}
2937
}
2938
}
2939
2940
/* Then mark the joined bodies and boundaries that are not conflicting */
2941
for(i=1;i<=data2->noelements;i++) {
2942
mat = data2->material[i];
2943
if( mat < MAXBODIES ) {
2944
if( !bodynameis[mat] ) {
2945
bodynameis[mat] = mat;
2946
bodyused[mat] = TRUE;
2947
if(!data1->bodyname[mat]) data1->bodyname[mat] = Cvector(0,MAXNAMESIZE);
2948
strcpy(data1->bodyname[mat],data2->bodyname[mat]);
2949
}
2950
}
2951
}
2952
2953
for(j=0;j < MAXBOUNDARIES;j++) {
2954
if(!bound2[j].created) continue;
2955
2956
for(i=1; i <= bound2[j].nosides; i++) {
2957
mat = bound2[j].types[i];
2958
if( mat < MAXBCS ) {
2959
if( !boundarynameis[mat] ) {
2960
boundarynameis[mat] = mat;
2961
boundaryused[mat] = TRUE;
2962
if(!data1->boundaryname[mat]) data1->boundaryname[mat] = Cvector(0,MAXNAMESIZE);
2963
strcpy(data1->boundaryname[mat],data2->boundaryname[mat]);
2964
}
2965
}
2966
}
2967
}
2968
2969
2970
/* And finally number the conflicting joined bodies and BCs */
2971
for(i=1;i<=data2->noelements;i++) {
2972
mat = data2->material[i];
2973
if( mat < MAXBODIES ) {
2974
if( bodynameis[mat] == -1) {
2975
for(k=1;k<MAXBODIES;k++)
2976
if(!bodyused[k]) break;
2977
if(info) printf("Renumbering body %d to %d\n",mat,k);
2978
bodynameis[mat] = k;
2979
bodyused[k] = TRUE;
2980
if(!data1->bodyname[k]) data1->bodyname[k] = Cvector(0,MAXNAMESIZE);
2981
strcpy(data1->bodyname[k],data2->bodyname[mat]);
2982
}
2983
}
2984
}
2985
2986
for(j=0;j < MAXBOUNDARIES;j++) {
2987
if(!bound2[j].created) continue;
2988
for(i=1; i <= bound2[j].nosides; i++) {
2989
mat = bound2[j].types[i];
2990
2991
if( mat < MAXBCS ) {
2992
if( boundarynameis[mat] == -1) {
2993
for(k=1;k<MAXBCS;k++)
2994
if(!boundaryused[k]) break;
2995
if(info) printf("Renumbering boundary %d to %d\n",mat,k);
2996
boundarynameis[mat] = k;
2997
boundaryused[k] = TRUE;
2998
if(!data1->boundaryname[k]) data1->boundaryname[k] = Cvector(0,MAXNAMESIZE);
2999
strcpy(data1->boundaryname[k],data2->boundaryname[mat]);
3000
}
3001
}
3002
}
3003
}
3004
3005
}
3006
else if (nooverlap ) {
3007
bcmax1 = 0;
3008
for(j=0;j < MAXBOUNDARIES;j++) {
3009
if(!bound1[j].created) continue;
3010
for(i=1; i <= bound1[k].nosides; i++) {
3011
mat = bound1[j].types[i];
3012
bcmax1 = MAX( bcmax1, mat );
3013
}
3014
}
3015
3016
bcmin2 = 1000;
3017
for(j=0;j < MAXBOUNDARIES;j++) {
3018
if(!bound2[j].created) continue;
3019
3020
for(i=1; i <= bound2[j].nosides; i++) {
3021
mat = bound2[j].types[i];
3022
bcmin2 = MIN( bcmin2, mat );
3023
}
3024
}
3025
bcoffset = MAX(0, bcmax1 - bcmin2 + 1);
3026
if( info ) {
3027
printf("Max(bc1) is %d and Min(bc2) is %d, using BC offset %d for mesh 2!\n",bcmax1,bcmin2,bcoffset);
3028
}
3029
3030
bodymax1 = 0;
3031
for(i=1;i<=data1->noelements;i++) {
3032
mat = data1->material[i];
3033
bodymax1 = MAX( bodymax1, mat );
3034
}
3035
3036
bodymin2 = 1000;
3037
for(i=1;i<=data2->noelements;i++) {
3038
mat = data2->material[i];
3039
bodymin2 = MIN( bodymin2, mat );
3040
}
3041
bodyoffset = MAX(0, bodymax1 - bodymin2 + 1);
3042
if( info ) {
3043
printf("Max(body1) is %d and Min(body2) is %d, using body offset %d for mesh 2!\n",bodymax1,bodymin2,bodyoffset);
3044
}
3045
}
3046
3047
3048
3049
for(j=0;j < MAXBOUNDARIES;j++) {
3050
if(!bound2[j].created) continue;
3051
3052
for(k=j;k < MAXBOUNDARIES;k++)
3053
if(!bound1[k].created) break;
3054
3055
bound1[k].created = bound2[j].created;
3056
bound1[k].nosides = bound2[j].nosides;
3057
bound1[k].coordsystem = bound2[j].coordsystem;
3058
bound1[k].side = bound2[j].side;
3059
bound1[k].side2 = bound2[j].side2;
3060
bound1[k].parent = bound2[j].parent;
3061
bound1[k].parent2 = bound2[j].parent2;
3062
bound1[k].material = bound2[j].material;
3063
bound1[k].echain = bound2[j].echain;
3064
bound1[k].types = bound2[j].types;
3065
bound1[k].normal = bound2[j].normal;
3066
3067
for(i=1; i <= bound1[k].nosides; i++) {
3068
bound1[k].parent[i] += data1->noelements;
3069
if(bound1[k].parent2[i])
3070
bound1[k].parent2[i] += data1->noelements;
3071
3072
mat = bound2[j].types[i];
3073
if( usenames ) {
3074
if( mat < MAXBCS ) {
3075
bound1[k].types[i] = boundarynameis[mat];
3076
}
3077
} else {
3078
bound1[k].types[i] = bcoffset + mat;
3079
}
3080
}
3081
}
3082
3083
data1->maxnodes = maxnodes;
3084
newtopo = Imatrix(1,noelements,0,maxnodes-1);
3085
newmaterial = Ivector(1,noelements);
3086
newelementtypes = Ivector(1,noelements);
3087
newx = Rvector(1,noknots);
3088
newy = Rvector(1,noknots);
3089
newz = Rvector(1,noknots);
3090
3091
for(i=1;i<=data1->noknots;i++) {
3092
newx[i] = data1->x[i];
3093
newy[i] = data1->y[i];
3094
newz[i] = data1->z[i];
3095
}
3096
for(i=1;i<=data2->noknots;i++) {
3097
newx[i+data1->noknots] = data2->x[i];
3098
newy[i+data1->noknots] = data2->y[i];
3099
newz[i+data1->noknots] = data2->z[i];
3100
}
3101
3102
for(i=1;i<=data1->noelements;i++) {
3103
mat = data1->material[i];
3104
newmaterial[i] = mat;
3105
newelementtypes[i] = data1->elementtypes[i];
3106
nonodes = newelementtypes[i]%100;
3107
for(j=0;j<nonodes;j++)
3108
newtopo[i][j] = data1->topology[i][j];
3109
}
3110
for(i=1;i<=data2->noelements;i++) {
3111
mat = data2->material[i];
3112
newelementtypes[i+data1->noelements] = data2->elementtypes[i];
3113
nonodes = newelementtypes[i+data1->noelements]%100;
3114
for(j=0;j<nonodes;j++)
3115
newtopo[i+data1->noelements][j] = data2->topology[i][j] + data1->noknots;
3116
3117
if( usenames ) {
3118
if( mat < MAXBODIES ) {
3119
newmaterial[i+data1->noelements] = bodynameis[mat];
3120
}
3121
}
3122
else {
3123
newmaterial[i+data1->noelements] = bodyoffset + mat;
3124
}
3125
}
3126
3127
free_Imatrix(data1->topology,1,data1->noelements,0,data1->maxnodes-1);
3128
free_Ivector(data1->material,1,data1->noelements);
3129
free_Rvector(data1->x,1,data1->noknots);
3130
free_Rvector(data1->y,1,data1->noknots);
3131
free_Rvector(data1->z,1,data1->noknots);
3132
3133
free_Imatrix(data2->topology,1,data2->noelements,0,data2->maxnodes-1);
3134
free_Ivector(data2->material,1,data2->noelements);
3135
free_Rvector(data2->x,1,data2->noknots);
3136
free_Rvector(data2->y,1,data2->noknots);
3137
free_Rvector(data2->z,1,data2->noknots);
3138
3139
data1->noelements = noelements;
3140
data1->noknots = noknots;
3141
data1->topology = newtopo;
3142
data1->material = newmaterial;
3143
data1->elementtypes = newelementtypes;
3144
data1->x = newx;
3145
data1->y = newy;
3146
data1->z = newz;
3147
3148
if(info) printf("Two meshes were united to one with %d nodes and %d elements.\n",
3149
noknots,noelements);
3150
3151
return(0);
3152
}
3153
3154
3155
int CloneMeshes(struct FemType *data,struct BoundaryType *bound,
3156
int *ncopies,Real *meshsize,int diffmats,int info)
3157
/* Unites two meshes for one larger mesh */
3158
{
3159
int i,j,k,l,m;
3160
int noelements,noknots,nonodes,totcopies,ind,origdim;
3161
int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL,maxnodes;
3162
int maxmaterial,maxtype,ncopy,bndr,nosides;
3163
Real *newx=NULL,*newy=NULL,*newz=NULL;
3164
Real maxcoord[3],mincoord[3];
3165
3166
int *vparent=NULL,*vparent2=NULL,*vside=NULL,*vside2=NULL;
3167
int *vtypes=NULL,*vmaterial=NULL,*vnormal=NULL,*vdiscont=NULL;
3168
3169
if(info) printf("CloneMeshes: copying the mesh to a matrix\n");
3170
if(diffmats) {
3171
if(info) printf("CloneMeshes: giving each new entity new material and bc indexes\n");
3172
}
3173
3174
origdim = data->dim;
3175
totcopies = 1;
3176
if( ncopies[2] > 1 ) {
3177
data->dim = 3;
3178
}
3179
else {
3180
ncopies[2] = 1;
3181
}
3182
3183
for(i=0;i<data->dim;i++) {
3184
if(ncopies[i] > 1) totcopies *= ncopies[i];
3185
}
3186
3187
maxcoord[0] = mincoord[0] = data->x[1];
3188
maxcoord[1] = mincoord[1] = data->y[1];
3189
maxcoord[2] = mincoord[2] = data->z[1];
3190
3191
for(i=1;i<=data->noknots;i++) {
3192
if(data->x[i] > maxcoord[0]) maxcoord[0] = data->x[i];
3193
if(data->x[i] < mincoord[0]) mincoord[0] = data->x[i];
3194
if(data->y[i] > maxcoord[1]) maxcoord[1] = data->y[i];
3195
if(data->y[i] < mincoord[1]) mincoord[1] = data->y[i];
3196
if(data->z[i] > maxcoord[2]) maxcoord[2] = data->z[i];
3197
if(data->z[i] < mincoord[2]) mincoord[2] = data->z[i];
3198
}
3199
3200
for(i=0;i<origdim;i++) {
3201
if(maxcoord[i]-mincoord[i] > meshsize[i]) meshsize[i] = maxcoord[i]-mincoord[i];
3202
}
3203
if(info) printf("Meshsize to be copied: %lg %lg %lg\n",meshsize[0],meshsize[1],meshsize[2]);
3204
3205
noknots = totcopies * data->noknots;
3206
noelements = totcopies * data->noelements;
3207
maxnodes = data->maxnodes;
3208
3209
if(info) printf("Copying the mesh to %d identical domains in %d-dim.\n",totcopies,data->dim);
3210
3211
data->maxnodes = maxnodes;
3212
newtopo = Imatrix(1,noelements,0,maxnodes-1);
3213
newmaterial = Ivector(1,noelements);
3214
newelementtypes = Ivector(1,noelements);
3215
newx = Rvector(1,noknots);
3216
newy = Rvector(1,noknots);
3217
newz = Rvector(1,noknots);
3218
3219
for(l=0;l<ncopies[2];l++) {
3220
for(k=0;k<ncopies[1];k++) {
3221
for(j=0;j<ncopies[0];j++) {
3222
for(i=1;i<=data->noknots;i++) {
3223
ncopy = j+k*ncopies[0]+l*ncopies[0]*ncopies[1];
3224
ind = i + ncopy*data->noknots;
3225
3226
newx[ind] = data->x[i] + j*meshsize[0];
3227
newy[ind] = data->y[i] + k*meshsize[1];
3228
newz[ind] = data->z[i] + l*meshsize[2];
3229
}
3230
}
3231
}
3232
}
3233
3234
maxmaterial = 0;
3235
if( diffmats ) {
3236
for(i=1;i<=data->noelements;i++)
3237
if(data->material[i] > maxmaterial) maxmaterial = data->material[i];
3238
if(info ) printf("Material offset for cloning set to: %d\n",maxmaterial);
3239
}
3240
3241
for(l=0;l<ncopies[2];l++) {
3242
for(k=0;k<ncopies[1];k++) {
3243
for(j=0;j<ncopies[0];j++) {
3244
for(i=1;i<=data->noelements;i++) {
3245
ncopy = j+k*ncopies[0]+l*ncopies[1]*ncopies[0];
3246
ind = i + ncopy*data->noelements;
3247
3248
newmaterial[ind] = data->material[i] + diffmats*maxmaterial*ncopy;
3249
newelementtypes[ind] = data->elementtypes[i];
3250
nonodes = newelementtypes[i]%100;
3251
for(m=0;m<nonodes;m++)
3252
newtopo[ind][m] = data->topology[i][m] + ncopy*data->noknots;
3253
}
3254
}
3255
}
3256
}
3257
3258
maxtype = 0;
3259
if( diffmats ) {
3260
for(j=0;j < MAXBOUNDARIES;j++) {
3261
if(!bound[j].created) continue;
3262
for(i=1; i <= bound[j].nosides; i++)
3263
if(maxtype < bound[j].types[i]) maxtype = bound[j].types[i];
3264
}
3265
if(info ) printf("Boundary offset for cloning set to: %d\n",maxtype);
3266
}
3267
3268
for(bndr=0;bndr < MAXBOUNDARIES;bndr++) {
3269
3270
if(!bound[bndr].created) continue;
3271
3272
nosides = totcopies * bound[bndr].nosides;
3273
3274
vparent = Ivector(1, nosides);
3275
vparent2 = Ivector(1, nosides);
3276
vside = Ivector(1, nosides);
3277
vside2 = Ivector(1, nosides);
3278
vmaterial = Ivector(1, nosides);
3279
vtypes = Ivector(1, nosides);
3280
vnormal = Ivector(1, nosides);
3281
3282
if(bound[bndr].ediscont) {
3283
vdiscont = Ivector(1, nosides);
3284
for(i=1; i <= nosides; i++)
3285
vdiscont[i] = 0;
3286
}
3287
3288
for(l=0;l<ncopies[2];l++) {
3289
for(k=0;k<ncopies[1];k++) {
3290
for(j=0;j<ncopies[0];j++) {
3291
for(i=1; i <= bound[bndr].nosides; i++) {
3292
3293
ncopy = j+k*ncopies[0]+l*ncopies[1]*ncopies[0];
3294
ind = i + ncopy * bound[bndr].nosides;
3295
3296
vparent[ind] = bound[bndr].parent[i] + ncopy * data->noelements;
3297
vside[ind] = bound[bndr].side[i];
3298
3299
if(bound[bndr].parent2[i]) {
3300
vparent2[ind] = bound[bndr].parent2[i] + ncopy * data->noelements;
3301
vside2[ind] = bound[bndr].side2[i];
3302
}
3303
else {
3304
vparent2[ind] = 0.0;
3305
vside2[ind] = 0.0;
3306
}
3307
3308
vnormal[ind] = bound[bndr].normal[i];
3309
3310
if(bound[bndr].ediscont)
3311
vdiscont[ind] = bound[bndr].discont[i];
3312
3313
vtypes[ind] = bound[bndr].types[i] + diffmats * ncopy * maxtype;
3314
3315
vmaterial[ind] = bound[bndr].material[i] + ncopy * maxmaterial;
3316
}
3317
}
3318
}
3319
}
3320
3321
bound[bndr].nosides = nosides;
3322
bound[bndr].side = vside;
3323
3324
bound[bndr].side2 = vside2;
3325
bound[bndr].parent = vparent;
3326
bound[bndr].parent2 = vparent2;
3327
bound[bndr].types = vtypes;
3328
bound[bndr].material = vmaterial;
3329
bound[bndr].normal = vnormal;
3330
if(bound[bndr].ediscont)
3331
bound[bndr].discont = vdiscont;
3332
}
3333
3334
free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes-1);
3335
free_Ivector(data->material,1,data->noelements);
3336
free_Rvector(data->x,1,data->noknots);
3337
free_Rvector(data->y,1,data->noknots);
3338
free_Rvector(data->z,1,data->noknots);
3339
3340
data->noelements = noelements;
3341
data->noknots = noknots;
3342
data->topology = newtopo;
3343
data->material = newmaterial;
3344
3345
data->elementtypes = newelementtypes;
3346
data->x = newx;
3347
data->y = newy;
3348
data->z = newz;
3349
3350
if( data->bodynamesexist || data->boundarynamesexist ) {
3351
printf("Cloning cannot treat names yet, omitting treatment of names for now!\n");
3352
data->bodynamesexist = FALSE;
3353
data->boundarynamesexist = FALSE;
3354
}
3355
3356
if(info) printf("The mesh was copied to several identical meshes\n");
3357
3358
return(0);
3359
}
3360
3361
3362
int MirrorMeshes(struct FemType *data,struct BoundaryType *bound,
3363
int *symmaxis,int diffmats,Real *meshsize,int symmbound,int info)
3364
/* Makes a mirror image of a mesh and unites it with the original mesh */
3365
{
3366
int i,j,m;
3367
int noelements,noknots,nonodes,totcopies,ind,maxnodes;
3368
int **newtopo=NULL,*newmaterial=NULL,*newelementtypes=NULL;
3369
int maxtype,bndr,nosides;
3370
Real *newx=NULL,*newy=NULL,*newz=NULL;
3371
Real maxcoord[3],mincoord[3];
3372
int ind0,elem0,axis1,axis2,axis3,symmcount;
3373
3374
int *vparent=NULL,*vparent2=NULL,*vside=NULL,*vside2=NULL;
3375
int *vtypes=NULL,*vmaterial=NULL,*vnormal=NULL,*vdiscont=NULL;
3376
3377
printf("MirrorMeshes: making a symmetric mapping of the mesh\n");
3378
3379
if(symmaxis[0]) symmaxis[0] = 1;
3380
if(symmaxis[1]) symmaxis[1] = 1;
3381
if(symmaxis[2]) symmaxis[2] = 1;
3382
if(data->dim < 3) symmaxis[2] = 0;
3383
3384
maxcoord[0] = mincoord[0] = data->x[1];
3385
maxcoord[1] = mincoord[1] = data->y[1];
3386
maxcoord[2] = mincoord[2] = data->z[1];
3387
3388
for(i=1;i<=data->noknots;i++) {
3389
if(data->x[i] > maxcoord[0]) maxcoord[0] = data->x[i];
3390
if(data->x[i] < mincoord[0]) mincoord[0] = data->x[i];
3391
if(data->y[i] > maxcoord[1]) maxcoord[1] = data->y[i];
3392
if(data->y[i] < mincoord[1]) mincoord[1] = data->y[i];
3393
if(data->z[i] > maxcoord[2]) maxcoord[2] = data->z[i];
3394
if(data->z[i] < mincoord[2]) mincoord[2] = data->z[i];
3395
}
3396
3397
for(i=0;i<3;i++) {
3398
if(maxcoord[i]-mincoord[i] > meshsize[i]) meshsize[i] = maxcoord[i]-mincoord[i];
3399
}
3400
3401
if(diffmats) diffmats = 1;
3402
3403
totcopies = 1;
3404
for(i=0;i<3;i++)
3405
if(symmaxis[i]) totcopies *= 2;
3406
3407
noknots = totcopies * data->noknots;
3408
noelements = totcopies * data->noelements;
3409
maxnodes = data->maxnodes;
3410
3411
printf("Mirroring the mesh to %d symmetrical domains.\n",totcopies);
3412
3413
data->maxnodes = maxnodes;
3414
newtopo = Imatrix(1,noelements,0,maxnodes-1);
3415
newmaterial = Ivector(1,noelements);
3416
newelementtypes = Ivector(1,noelements);
3417
newx = Rvector(1,noknots);
3418
newy = Rvector(1,noknots);
3419
newz = Rvector(1,noknots);
3420
3421
ind0 = 0;
3422
3423
3424
for(axis1=0;axis1 <= symmaxis[0];axis1++) {
3425
for(axis2=0;axis2 <= symmaxis[1];axis2++) {
3426
for(axis3=0;axis3 <= symmaxis[2];axis3++) {
3427
3428
for(i=1;i<=data->noknots;i++) {
3429
ind = i + ind0;
3430
3431
newx[ind] = (1-2*axis1) * data->x[i];
3432
newy[ind] = (1-2*axis2) * data->y[i];
3433
newz[ind] = (1-2*axis3) * data->z[i];
3434
3435
newmaterial[ind] = data->material[i];
3436
newelementtypes[ind] = data->elementtypes[i];
3437
}
3438
ind0 += data->noknots;
3439
}
3440
}
3441
}
3442
3443
elem0 = 0;
3444
ind0 = 0;
3445
3446
for(axis1=0;axis1 <= symmaxis[0];axis1++) {
3447
for(axis2=0;axis2 <= symmaxis[1];axis2++) {
3448
for(axis3=0;axis3 <= symmaxis[2];axis3++) {
3449
3450
for(i=1;i<=data->noelements;i++) {
3451
ind = i + elem0;
3452
newmaterial[ind] = data->material[i];
3453
newelementtypes[ind] = data->elementtypes[i];
3454
nonodes = newelementtypes[i]%100;
3455
for(m=0;m<nonodes;m++)
3456
newtopo[ind][m] = data->topology[i][m] + ind0;
3457
}
3458
3459
elem0 += data->noelements;
3460
ind0 += data->noknots;
3461
printf("elem0=%d ind0=%d\n",elem0,ind0);
3462
}
3463
}
3464
}
3465
3466
maxtype = 0;
3467
for(j=0;j < MAXBOUNDARIES;j++) {
3468
if(!bound[j].created) continue;
3469
for(i=1; i <= bound[j].nosides; i++)
3470
if(maxtype < bound[j].types[i]) maxtype = bound[j].types[i];
3471
}
3472
3473
for(bndr=0;bndr < MAXBOUNDARIES;bndr++) {
3474
3475
if(!bound[bndr].created) continue;
3476
nosides = totcopies * bound[bndr].nosides;
3477
ind = 0;
3478
3479
vparent = Ivector(1, nosides);
3480
vparent2 = Ivector(1, nosides);
3481
vside = Ivector(1, nosides);
3482
vside2 = Ivector(1, nosides);
3483
vmaterial = Ivector(1, nosides);
3484
vtypes = Ivector(1, nosides);
3485
vnormal = Ivector(1, nosides);
3486
3487
if(bound[bndr].ediscont) {
3488
vdiscont = Ivector(1, nosides);
3489
for(i=1;i<=nosides;i++)
3490
vdiscont[i] = 0;
3491
}
3492
3493
symmcount = 0;
3494
elem0 = 0;
3495
ind0 = 0;
3496
3497
for(axis1=0;axis1 <= symmaxis[0];axis1++) {
3498
for(axis2=0;axis2 <= symmaxis[1];axis2++) {
3499
for(axis3=0;axis3 <= symmaxis[2];axis3++) {
3500
3501
for(i=1; i <= bound[bndr].nosides; i++) {
3502
3503
if(bound[bndr].types[i] == symmbound) continue;
3504
ind++;
3505
3506
vparent[ind] = bound[bndr].parent[i] + elem0;
3507
vparent2[ind] = bound[bndr].parent2[i] + elem0;
3508
vside[ind] = bound[bndr].side[i];
3509
vside2[ind] = bound[bndr].side2[i];
3510
3511
vnormal[ind] = bound[bndr].normal[i];
3512
3513
if(bound[bndr].ediscont)
3514
vdiscont[ind] = bound[bndr].discont[i];
3515
3516
vtypes[ind] = bound[bndr].types[i] + diffmats * symmcount * maxtype;
3517
3518
vmaterial[ind] = bound[bndr].material[i];
3519
}
3520
3521
symmcount++;
3522
elem0 += data->noelements;
3523
}
3524
}
3525
}
3526
3527
nosides = ind;
3528
bound[bndr].nosides = nosides;
3529
bound[bndr].side = vside;
3530
bound[bndr].side2 = vside2;
3531
bound[bndr].parent = vparent;
3532
bound[bndr].parent2 = vparent2;
3533
bound[bndr].types = vtypes;
3534
bound[bndr].material = vmaterial;
3535
bound[bndr].normal = vnormal;
3536
if(bound[bndr].ediscont)
3537
bound[bndr].discont = vdiscont;
3538
}
3539
3540
free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes-1);
3541
free_Ivector(data->material,1,data->noelements);
3542
free_Rvector(data->x,1,data->noknots);
3543
free_Rvector(data->y,1,data->noknots);
3544
free_Rvector(data->z,1,data->noknots);
3545
3546
data->noelements = noelements;
3547
data->noknots = noknots;
3548
data->topology = newtopo;
3549
data->material = newmaterial;
3550
data->elementtypes = newelementtypes;
3551
data->x = newx;
3552
data->y = newy;
3553
data->z = newz;
3554
3555
if( data->bodynamesexist || data->boundarynamesexist ) {
3556
printf("Mirroring cannot treat names yet, omitting treatment of names for now!\n");
3557
data->bodynamesexist = FALSE;
3558
data->boundarynamesexist = FALSE;
3559
}
3560
3561
if(info) printf("The mesh was copied to several identical meshes\n");
3562
3563
return(0);
3564
}
3565
3566
3567
3568
static void ReorderAutomatic(struct FemType *data,int iterations,
3569
int *origindx,Real corder[],int info)
3570
{
3571
int i,j,k,l,nonodes,maxnodes,noelements,noknots,minwidth,indexwidth;
3572
int **neighbours=NULL,*newrank=NULL,*newindx=NULL,*oldrank=NULL,*oldindx=NULL;
3573
int nocands,*cands=NULL,ind,ind2,cantdo;
3574
int elemtype,indready,iter,*localorder=NULL,*localtmp=NULL,nolocal;
3575
Real *localdist=NULL,dx,dy,dz;
3576
3577
iterations = 3;
3578
iter = 0;
3579
maxnodes = 8;
3580
3581
noelements = data->noelements;
3582
noknots = data->noknots;
3583
3584
cantdo = FALSE;
3585
for(j=1;j<=noelements;j++) {
3586
elemtype = data->elementtypes[j];
3587
if(elemtype != 404 && elemtype != 303 && elemtype != 808) cantdo = elemtype;
3588
}
3589
if(cantdo) {
3590
printf("Automatic reordering not specified for elementtype %d\n",cantdo);
3591
return;
3592
}
3593
3594
printf("Allocating...\n");
3595
3596
cands = Ivector(1,maxnodes);
3597
localorder = Ivector(1,maxnodes);
3598
localtmp = Ivector(1,maxnodes);
3599
localdist = Rvector(1,maxnodes);
3600
3601
neighbours = Imatrix(1,noknots,1,maxnodes);
3602
newrank = Ivector(1,noknots);
3603
oldrank = Ivector(1,noknots);
3604
newindx = Ivector(1,noknots);
3605
oldindx = Ivector(1,noknots);
3606
3607
for(i=1;i<=noknots;i++)
3608
oldindx[i] = origindx[i];
3609
3610
for(i=1;i<=noknots;i++)
3611
oldrank[origindx[i]] = i;
3612
3613
minwidth = CalculateIndexwidth(data,TRUE,oldrank);
3614
if(info) printf("Indexwidth of the initial node order is %d.\n",minwidth);
3615
3616
for(j=1;j<=noknots;j++)
3617
for(i=1;i<=maxnodes;i++)
3618
neighbours[j][i] = 0;
3619
3620
3621
if(info) printf("Initializing neighbours\n");
3622
3623
for(j=1;j<=noelements;j++) {
3624
elemtype = data->elementtypes[j];
3625
nonodes = elemtype%100;
3626
nocands = 0;
3627
3628
for(i=0;i<nonodes;i++) {
3629
ind = data->topology[j][i];
3630
3631
if(elemtype == 404 || elemtype == 303) {
3632
nocands = 2;
3633
cands[1] = (i+1)%nonodes;
3634
cands[2] = (i+nonodes-1)%nonodes;
3635
}
3636
else if(elemtype == 808) {
3637
nocands = 3;
3638
if(i<4) {
3639
cands[1] = (i+1)%4;
3640
cands[2] = (i+3)%4;
3641
cands[3] = i+4;
3642
}
3643
else {
3644
cands[1] = (i-4+1)%4+4;
3645
cands[2] = (i-4+3)%4+4;
3646
cands[3] = i-4;
3647
}
3648
}
3649
3650
for(k=1;k<=nocands;k++) {
3651
ind2 = data->topology[j][cands[k]];
3652
for(l=1;l<=maxnodes;l++) {
3653
if(neighbours[ind][l] == 0) break;
3654
if(neighbours[ind][l] == ind2) ind2 = 0;
3655
}
3656
if(ind2) neighbours[ind][l] = ind2;
3657
}
3658
}
3659
}
3660
3661
#if 0
3662
for(j=1;j<=noknots;j++) {
3663
printf("neighbours[%d]= ",j);
3664
for(l=1;l<=maxnodes;l++)
3665
printf("%d ",neighbours[j][l]);
3666
printf("\n");
3667
}
3668
#endif
3669
3670
if(info) printf("Reordering neighbours table\n");
3671
3672
for(j=1;j<=noknots;j++) {
3673
3674
nolocal = 0;
3675
dz = 0.0;
3676
3677
for(l=1;l<=maxnodes;l++){
3678
if((ind = neighbours[j][l])) {
3679
nolocal++;
3680
localtmp[l] = ind;
3681
dx = data->x[l] - data->x[ind];
3682
dy = data->y[l] - data->y[ind];
3683
dz = data->z[l] - data->z[ind];
3684
localdist[l] = corder[0]*fabs(dx) + corder[1]*fabs(dy) + corder[2]*fabs(dz);
3685
}
3686
}
3687
3688
SortIndex(nolocal,localdist,localorder);
3689
3690
for(l=1;l<=nolocal;l++)
3691
neighbours[j][l] = localtmp[localorder[l]];
3692
3693
#if 0
3694
for(l=1;l<=nolocal;l++)
3695
printf("j=%d l=%d dist=%.3le order=%d %d\n",
3696
j,l,localdist[l],localorder[l],neighbours[j][l]);
3697
#endif
3698
}
3699
3700
3701
3702
for(iter=1;iter<=iterations;iter++) {
3703
3704
if(info) printf("Optimal topology testing %d\n",iter);
3705
3706
for(i=1;i<=noknots;i++)
3707
newrank[i] = 0;
3708
3709
ind = 0;
3710
indready = 1;
3711
3712
do {
3713
if(indready > ind) {
3714
for(l=noknots;l>=1;l--)
3715
if(j = oldindx[l]) break;
3716
if(info) printf("Starting over from node %d when ind=%d indready=%d\n",j,ind,indready);
3717
}
3718
else {
3719
j = newindx[indready] ;
3720
}
3721
3722
for(l=1;ind2 = neighbours[j][l];l++) {
3723
if(ind2) {
3724
if(!newrank[ind2]) {
3725
ind++;
3726
newrank[ind2] = ind;
3727
newindx[ind] = ind2;
3728
oldindx[oldrank[ind2]] = 0;
3729
oldrank[ind2] = 0;
3730
}
3731
}
3732
}
3733
indready++;
3734
3735
} while(ind < noknots);
3736
3737
indexwidth = CalculateIndexwidth(data,TRUE,newrank);
3738
if(info) printf("Indexwidth of the suggested node order is %d.\n",indexwidth);
3739
3740
for(i=1;i<=noknots;i++)
3741
oldrank[i] = newrank[i];
3742
3743
for(i=1;i<=noknots;i++)
3744
oldindx[i] = newindx[i];
3745
3746
if(indexwidth < minwidth) {
3747
for(i=1;i<=noknots;i++)
3748
origindx[i] = newindx[i];
3749
minwidth = indexwidth;
3750
}
3751
}
3752
3753
free_Ivector(cands,1,maxnodes);
3754
free_Ivector(localorder,1,maxnodes);
3755
free_Ivector(localtmp,1,maxnodes);
3756
free_Rvector(localdist,1,maxnodes);
3757
3758
free_Imatrix(neighbours,1,noknots,1,maxnodes);
3759
free_Ivector(newrank,1,noknots);
3760
free_Ivector(oldrank,1,noknots);
3761
free_Ivector(newindx,1,noknots);
3762
free_Ivector(oldindx,1,noknots);
3763
}
3764
3765
3766
3767
3768
void ReorderElements(struct FemType *data,struct BoundaryType *bound,
3769
int manual,Real corder[],int info)
3770
{
3771
int i,j,k;
3772
int noelements,noknots,nonodes,length;
3773
int **newtopology=NULL,*newmaterial=NULL,*newelementtypes=NULL;
3774
int *indx=NULL,*revindx=NULL,*elemindx=NULL,*revelemindx=NULL;
3775
int oldnoknots, oldnoelements;
3776
Real *newx=NULL,*newy=NULL,*newz=NULL,*arrange=NULL;
3777
Real dx,dy,dz,cx,cy,cz,cbase;
3778
3779
noelements = oldnoelements = data->noelements;
3780
noknots = oldnoknots = data->noknots;
3781
3782
if(info) printf("Reordering %d knots and %d elements in %d-dimensions.\n",
3783
noknots,noelements,data->dim);
3784
3785
if(noelements > noknots)
3786
length = noelements;
3787
else
3788
length = noknots;
3789
3790
arrange = Rvector(1,length);
3791
indx = Ivector(1,noknots);
3792
revindx = Ivector(1,noknots);
3793
elemindx = Ivector(1,noelements);
3794
revelemindx = Ivector(1,noelements);
3795
3796
if(manual == 1) {
3797
cx = corder[0];
3798
cy = corder[1];
3799
cz = corder[2];
3800
}
3801
else {
3802
Real xmin,xmax,ymin,ymax,zmin,zmax;
3803
xmin = xmax = data->x[1];
3804
ymin = ymax = data->y[1];
3805
zmin = zmax = data->z[1];
3806
3807
for(i=1;i<=data->noknots;i++) {
3808
if(xmin > data->x[i]) xmin = data->x[i];
3809
if(xmax < data->x[i]) xmax = data->x[i];
3810
if(ymin > data->y[i]) ymin = data->y[i];
3811
if(ymax < data->y[i]) ymax = data->y[i];
3812
if(zmin > data->z[i]) zmin = data->z[i];
3813
if(zmax < data->z[i]) zmax = data->z[i];
3814
}
3815
dx = xmax-xmin;
3816
dy = ymax-ymin;
3817
dz = zmax-zmin;
3818
3819
/* The second strategy seems to be better in many cases */
3820
cbase = 100.0;
3821
cx = pow(cbase,1.0*(dx>dy)+1.0*(dx>dz));
3822
cy = pow(cbase,1.0*(dy>dx)+1.0*(dy>dz));
3823
cz = pow(cbase,1.0*(dz>dx)+1.0*(dz>dx));
3824
3825
corder[0] = cx;
3826
corder[1] = cy;
3827
corder[2] = cz;
3828
}
3829
3830
if(info) printf("Ordering with (%.3lg*x + %.3lg*y + %.3lg*z)\n",cx,cy,cz);
3831
for(i=1;i<=noknots;i++) {
3832
arrange[i] = cx*data->x[i] + cy*data->y[i] + cz*data->z[i];
3833
}
3834
SortIndex(noknots,arrange,indx);
3835
3836
if(manual == 2) ReorderAutomatic(data,0,indx,corder,TRUE);
3837
3838
for(i=1;i<=noknots;i++)
3839
revindx[indx[i]] = i;
3840
3841
3842
for(j=1;j<=noelements;j++) {
3843
nonodes = data->elementtypes[j]%100;
3844
arrange[j] = 0.0;
3845
for(i=0;i<nonodes;i++) {
3846
k = data->topology[j][i];
3847
arrange[j] += cx*data->x[k] + cy*data->y[k] + cz*data->z[k];
3848
}
3849
}
3850
3851
SortIndex(noelements,arrange,elemindx);
3852
for(i=1;i<=noelements;i++)
3853
revelemindx[elemindx[i]] = i;
3854
3855
3856
#if 0
3857
for(i=1;i<=noknots;i++)
3858
printf("i=%d indx=%d revi=%d f=%.2lg\n",
3859
i,indx[i],revindx[i],arrange[indx[i]]);
3860
#endif
3861
3862
if(info) printf("Moving knots to new positions\n");
3863
newx = Rvector(1,data->noknots);
3864
newy = Rvector(1,data->noknots);
3865
newz = Rvector(1,data->noknots);
3866
3867
for(i=1;i<=data->noknots;i++) {
3868
newx[i] = data->x[indx[i]];
3869
newy[i] = data->y[indx[i]];
3870
newz[i] = data->z[indx[i]];
3871
}
3872
3873
free_Rvector(data->x,1,data->noknots);
3874
free_Rvector(data->y,1,data->noknots);
3875
free_Rvector(data->z,1,data->noknots);
3876
3877
data->x = newx;
3878
data->y = newy;
3879
data->z = newz;
3880
3881
if(info) printf("Moving the elements to new positions\n");
3882
3883
newtopology = Imatrix(1,noelements,0,data->maxnodes-1);
3884
newmaterial = Ivector(1,noelements);
3885
newelementtypes = Ivector(1,noelements);
3886
3887
for(j=1;j<=noelements;j++) {
3888
newmaterial[j] = data->material[elemindx[j]];
3889
newelementtypes[j] = data->elementtypes[elemindx[j]];
3890
nonodes = newelementtypes[j]%100;
3891
for(i=0;i<nonodes;i++) {
3892
k = data->topology[elemindx[j]][i];
3893
newtopology[j][i] = revindx[k];
3894
}
3895
}
3896
3897
data->material = newmaterial;
3898
data->elementtypes = newelementtypes;
3899
data->topology = newtopology;
3900
3901
3902
printf("Moving the parents of the boundary nodes.\n");
3903
for(j=0;j < MAXBOUNDARIES;j++) {
3904
3905
if(!bound[j].created) continue;
3906
3907
for(i=1; i <= bound[j].nosides; i++) {
3908
3909
bound[j].parent[i] = revelemindx[bound[j].parent[i]];
3910
3911
if(bound[j].parent2[i])
3912
bound[j].parent2[i] = revelemindx[bound[j].parent2[i]];
3913
}
3914
}
3915
3916
i = CalculateIndexwidth(data,FALSE,indx);
3917
printf("Indexwidth of the new node order is %d.\n",i);
3918
3919
free_Rvector(arrange,1,length);
3920
free_Ivector(indx,1,oldnoknots);
3921
free_Ivector(revindx,1,oldnoknots);
3922
free_Ivector(elemindx,1,oldnoelements);
3923
free_Ivector(revelemindx,1,oldnoelements);
3924
}
3925
3926
3927
3928
int RemoveUnusedNodes(struct FemType *data,int info)
3929
{
3930
int i,j;
3931
int noelements,noknots,nonodes,activeknots;
3932
int *indx;
3933
3934
noelements = data->noelements;
3935
noknots = data->noknots;
3936
3937
indx = Ivector(1,noknots);
3938
for(i=1;i<=noknots;i++) indx[i] = 0;
3939
3940
for(j=1;j<=noelements;j++) {
3941
nonodes = data->elementtypes[j] % 100;
3942
for(i=0;i<nonodes;i++)
3943
indx[ data->topology[j][i] ] = 1;
3944
}
3945
3946
activeknots = 0;
3947
j = 0;
3948
for(i=1;i<=noknots;i++) {
3949
if(indx[i]) {
3950
activeknots += 1;
3951
indx[i] = activeknots;
3952
}
3953
else {
3954
j++;
3955
if(j<=5) printf("Unused node index in mesh: %d\n",i);
3956
}
3957
}
3958
3959
if( noknots == activeknots) {
3960
if(info) printf("All %d nodes were used by the mesh elements\n",noknots);
3961
return(1);
3962
}
3963
3964
if(info) printf("Removing %d unused nodes (out of %d) from the mesh\n",noknots-activeknots,noknots);
3965
3966
for(j=1;j<=noelements;j++) {
3967
nonodes = data->elementtypes[j] % 100;
3968
for(i=0;i<nonodes;i++)
3969
data->topology[j][i] = indx[ data->topology[j][i] ];
3970
}
3971
3972
for(i=1;i<=noknots;i++) {
3973
j = indx[i];
3974
if(!j) continue;
3975
data->x[j] = data->x[i];
3976
data->y[j] = data->y[i];
3977
data->z[j] = data->z[i];
3978
}
3979
data->noknots = activeknots;
3980
3981
free_Ivector(indx,1,noknots);
3982
3983
return(0);
3984
}
3985
3986
3987
3988
3989
void RenumberBoundaryTypes(struct FemType *data,struct BoundaryType *bound,
3990
int renumber, int bcoffset, int info)
3991
{
3992
int i,j,k,doinit,isordered;
3993
int minbc=0,maxbc=0,**mapbc;
3994
int elemdim=0,elemtype=0,sideind[MAXNODESD1];
3995
int bctype,havename,isname;
3996
3997
if(renumber) {
3998
if(0) printf("Renumbering boundary types\n");
3999
4000
doinit = TRUE;
4001
for(j=0;j < MAXBOUNDARIES;j++) {
4002
if(!bound[j].created) continue;
4003
4004
for(i=1;i<=bound[j].nosides;i++) {
4005
if(doinit) {
4006
maxbc = minbc = bound[j].types[i];
4007
doinit = FALSE;
4008
}
4009
maxbc = MAX(maxbc,bound[j].types[i]);
4010
minbc = MIN(minbc,bound[j].types[i]);
4011
}
4012
}
4013
if(doinit) return;
4014
4015
if(info) printf("Initial boundary interval [%d,%d]\n",minbc,maxbc);
4016
4017
mapbc = Imatrix(minbc,maxbc,0,2);
4018
for(i=minbc;i<=maxbc;i++)
4019
for(j=0;j<=2;j++)
4020
mapbc[i][j] = 0;
4021
4022
for(j=0;j < MAXBOUNDARIES;j++) {
4023
if(!bound[j].created) continue;
4024
for(i=1;i<=bound[j].nosides;i++) {
4025
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],data,sideind,&elemtype);
4026
if(!elemtype) printf("could not find boundary element: %d %d %d\n",i,j,bound[j].parent[i]);
4027
elemdim = GetElementDimension(elemtype);
4028
bctype = bound[j].types[i];
4029
4030
if(0) printf("type and dim: %d %d %d\n",elemtype,elemdim,bctype);
4031
4032
mapbc[bctype][elemdim] += 1;
4033
}
4034
}
4035
4036
if(0) {
4037
for(i=minbc;i<=maxbc;i++)
4038
for(j=0;j<=2;j++)
4039
if(mapbc[i][j]) printf("bc map1: %d %d\n",i,mapbc[i][j]);
4040
}
4041
4042
j = 0;
4043
/* Give the larger dimension always a smaller BC type */
4044
isordered = TRUE;
4045
for(isname=1;isname>=0;isname--) {
4046
for(elemdim=2;elemdim>=0;elemdim--) {
4047
for(i=minbc;i<=maxbc;i++) {
4048
if(!mapbc[i][elemdim]) continue;
4049
4050
/* Give index 1st to the named entities, then to unnamed. */
4051
havename = FALSE;
4052
if(data->boundarynamesexist) {
4053
if(i<MAXBCS) {
4054
if(data->boundaryname[i]) havename = TRUE;
4055
}
4056
}
4057
if(havename != isname) break;
4058
4059
j++;
4060
if(i == j) {
4061
if( isname ) {
4062
printf("BC index unaltered %d in %d %dD elements of %s\n",i,mapbc[i][elemdim],elemdim,data->boundaryname[i]);
4063
}
4064
else {
4065
printf("BC index unaltered %d in %d %dD elements\n",i,mapbc[i][elemdim],elemdim);
4066
}
4067
}
4068
else {
4069
isordered = FALSE;
4070
if( isname ) {
4071
printf("BC index changed %d -> %d in %d %dD elements of %s\n",i,j,mapbc[i][elemdim],elemdim,data->boundaryname[i]);
4072
}
4073
else {
4074
printf("BC index changed %d -> %d in %d %dD elements\n",i,j,mapbc[i][elemdim],elemdim);
4075
}
4076
}
4077
mapbc[i][elemdim] = j;
4078
}
4079
}
4080
}
4081
4082
if(0) {
4083
for(i=minbc;i<=maxbc;i++)
4084
for(j=0;j<=2;j++)
4085
if(mapbc[i][j]) printf("bc map2: %d %d\n",i,mapbc[i][j]);
4086
}
4087
4088
if(isordered) {
4089
if(info) printf("Numbering of boundary types is already ok\n");
4090
}
4091
else {
4092
if(info) printf("Mapping boundary types from [%d %d] to [%d %d]\n",minbc,maxbc,1,j);
4093
4094
for(j=0;j < MAXBOUNDARIES;j++) {
4095
if(!bound[j].created) continue;
4096
for(i=1;i<=bound[j].nosides;i++) {
4097
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],data,sideind,&elemtype);
4098
elemdim = GetElementDimension(elemtype);
4099
bound[j].types[i] = mapbc[bound[j].types[i]][elemdim];
4100
}
4101
}
4102
4103
if(data->boundarynamesexist) {
4104
char *boundaryname0[MAXBCS];
4105
4106
for(j=0;j<MAXBODIES;j++)
4107
boundaryname0[j] = NULL;
4108
4109
/* We need some temporal place is name mapping might not be unique */
4110
for(j=minbc;j<=MIN(maxbc,MAXBCS-1);j++) {
4111
k = 0;
4112
for(elemdim=2;elemdim>=0;elemdim--) {
4113
k = mapbc[j][elemdim];
4114
if(k) break;
4115
}
4116
if(k) {
4117
if(data->boundaryname[j]) {
4118
boundaryname0[j] = Cvector(0,MAXNAMESIZE);
4119
strcpy(boundaryname0[j],data->boundaryname[j]);
4120
free_Cvector(data->boundaryname[j],0,MAXNAMESIZE);
4121
data->boundaryname[j] = NULL;
4122
}
4123
}
4124
}
4125
4126
for(j=minbc;j<=MIN(maxbc,MAXBCS-1);j++) {
4127
k = 0;
4128
for(elemdim=2;elemdim>=0;elemdim--) {
4129
k = mapbc[j][elemdim];
4130
if(k) break;
4131
}
4132
if(k) {
4133
if(boundaryname0[j]) {
4134
if(!data->boundaryname[k])
4135
data->boundaryname[k] = Cvector(0,MAXNAMESIZE);
4136
strcpy(data->boundaryname[k],boundaryname0[j]);
4137
}
4138
}
4139
}
4140
}
4141
}
4142
free_Imatrix(mapbc,minbc,maxbc,0,2);
4143
}
4144
4145
if(bcoffset) {
4146
if(info) printf("Adding offset of %d to the BCs\n",bcoffset);
4147
for(j=0;j < MAXBOUNDARIES;j++) {
4148
if(!bound[j].created) continue;
4149
for(i=1;i<=bound[j].nosides;i++)
4150
bound[j].types[i] += bcoffset;
4151
}
4152
if(data->boundarynamesexist) {
4153
for(j=MAXBCS-bcoffset-1;j>=0;j--) {
4154
k = j+bcoffset;
4155
if(!data->boundaryname[k]) data->boundaryname[k] = Cvector(0,MAXNAMESIZE);
4156
strcpy(data->boundaryname[k],data->boundaryname[j]);
4157
}
4158
}
4159
}
4160
}
4161
4162
4163
4164
void RenumberMaterialTypes(struct FemType *data,struct BoundaryType *bound,int info)
4165
{
4166
int i,j,k,noelements,doinit;
4167
int minmat=0,maxmat=0,*mapmat;
4168
4169
if(0) printf("Setting new material types\n");
4170
4171
noelements = data->noelements;
4172
if(noelements < 1) {
4173
printf("There are no elements to set!\n");
4174
return;
4175
}
4176
4177
doinit = TRUE;
4178
for(j=1;j<=noelements;j++) {
4179
if(doinit) {
4180
maxmat = minmat = data->material[j];
4181
doinit = FALSE;
4182
}
4183
maxmat = MAX(maxmat,data->material[j]);
4184
minmat = MIN(minmat,data->material[j]);
4185
}
4186
4187
if(info) printf("Initial body interval [%d,%d]\n",minmat,maxmat);
4188
4189
mapmat = Ivector(minmat,maxmat);
4190
for(i=minmat;i<=maxmat;i++) mapmat[i] = 0;
4191
4192
for(j=1;j<=noelements;j++)
4193
mapmat[data->material[j]] += 1;
4194
4195
j = 0;
4196
for(i=minmat;i<=maxmat;i++) {
4197
if(mapmat[i]) {
4198
j++;
4199
if(i != j) printf("body index changed %d -> %d in %d elements\n",i,j,mapmat[i]);
4200
mapmat[i] = j;
4201
}
4202
}
4203
4204
if(maxmat - minmat >= j || minmat != 1) {
4205
if(info) printf("Mapping material types from [%d %d] to [%d %d]\n",
4206
minmat,maxmat,1,j);
4207
for(j=1;j<=noelements;j++)
4208
data->material[j] = mapmat[data->material[j]];
4209
4210
if(data->bodynamesexist) {
4211
if(info) printf("Mapping entity names to follow material indexes\n");
4212
for(j=minmat;j<=MIN(maxmat,MAXBODIES-1);j++) {
4213
k = mapmat[j];
4214
if(k) {
4215
if(data->bodyname[j]) {
4216
if(!data->bodyname[k]) data->bodyname[k] = Cvector(0,MAXNAMESIZE);
4217
strcpy(data->bodyname[k],data->bodyname[j]);
4218
}
4219
}
4220
}
4221
}
4222
}
4223
else {
4224
if(info) printf("Numbering of bodies is already ok\n");
4225
}
4226
4227
free_Ivector(mapmat,minmat,maxmat);
4228
4229
if(info) printf("Renumbering of material types completed!\n");
4230
}
4231
4232
4233
4234
int RemoveLowerDimensionalBoundaries(struct FemType *data,struct BoundaryType *bound,int info)
4235
{
4236
int i,j,noelements;
4237
int elemtype,maxelemdim,minelemdim,elemdim;
4238
int parent, side, sideind[MAXNODESD1],sideelemtype;
4239
int nosides, oldnosides,newnosides;
4240
4241
if(info) printf("Removing lower dimensional boundaries\n");
4242
4243
noelements = data->noelements;
4244
if(noelements < 1) return(1);
4245
4246
elemtype = GetMaxElementType(data);
4247
4248
maxelemdim = GetElementDimension(elemtype);
4249
4250
if(info) printf("Maximum elementtype is %d and dimension %d\n",elemtype,maxelemdim);
4251
4252
elemtype = GetMinElementType(data);
4253
minelemdim = GetElementDimension(elemtype);
4254
if(info) printf("Minimum elementtype is %d and dimension %d\n",elemtype,minelemdim);
4255
4256
/* Nothing to remove if the bulk mesh has 1D elements */
4257
if(minelemdim < 2) return(2);
4258
4259
oldnosides = 0;
4260
newnosides = 0;
4261
for(j=0;j < MAXBOUNDARIES;j++) {
4262
nosides = 0;
4263
if(!bound[j].created) continue;
4264
for(i=1;i<=bound[j].nosides;i++) {
4265
4266
oldnosides++;
4267
parent = bound[j].parent[i];
4268
4269
side = bound[j].side[i];
4270
4271
GetBoundaryElement(i,&bound[j],data,sideind,&sideelemtype);
4272
/* Old: GetElementSide(parent,side,1,data,sideind,&sideelemtype); */
4273
4274
elemdim = GetElementDimension(sideelemtype);
4275
4276
/* if(maxelemdim - elemdim > 1) continue; */
4277
/* This was changed as we want to maintain 1D BCs of a hybrid 2D/3D mesh. */
4278
if(minelemdim - elemdim > 1) continue;
4279
4280
nosides++;
4281
if(nosides == i) continue;
4282
4283
bound[j].parent[nosides] = bound[j].parent[i];
4284
bound[j].parent2[nosides] = bound[j].parent2[i];
4285
bound[j].side[nosides] = bound[j].side[i];
4286
bound[j].side2[nosides] = bound[j].side2[i];
4287
bound[j].types[nosides] = bound[j].types[i];
4288
}
4289
bound[j].nosides = nosides;
4290
newnosides += nosides;
4291
}
4292
4293
if(info) printf("Removed %d (out of %d) less than %dD boundary elements\n",
4294
oldnosides-newnosides,oldnosides,minelemdim-1);
4295
return(0);
4296
}
4297
4298
int RemoveInternalBoundaries(struct FemType *data,struct BoundaryType *bound,int info)
4299
{
4300
int i,j;
4301
int parent,parent2;
4302
int nosides,oldnosides,newnosides;
4303
4304
if(info) printf("Removing internal boundaries\n");
4305
4306
if( data->noelements < 1 ) return(1);
4307
4308
oldnosides = 0;
4309
newnosides = 0;
4310
for(j=0;j < MAXBOUNDARIES;j++) {
4311
nosides = 0;
4312
if(!bound[j].created) continue;
4313
for(i=1;i<=bound[j].nosides;i++) {
4314
4315
oldnosides++;
4316
parent = bound[j].parent[i];
4317
parent2 = bound[j].parent2[i];
4318
4319
if( parent > 0 && parent2 > 0 ) continue;
4320
4321
nosides++;
4322
if(nosides == i) continue;
4323
4324
bound[j].parent[nosides] = bound[j].parent[i];
4325
bound[j].parent2[nosides] = bound[j].parent2[i];
4326
bound[j].side[nosides] = bound[j].side[i];
4327
bound[j].side2[nosides] = bound[j].side2[i];
4328
bound[j].types[nosides] = bound[j].types[i];
4329
}
4330
bound[j].nosides = nosides;
4331
newnosides += nosides;
4332
}
4333
4334
if(info) printf("Removed %d (out of %d) internal boundary elements\n",
4335
oldnosides-newnosides,oldnosides);
4336
return(0);
4337
}
4338
4339
4340
#if 0
4341
static void FindEdges(struct FemType *data,struct BoundaryType *bound,
4342
int material,int sidetype,int info)
4343
{
4344
int i,j,side,identical,noelements,element;
4345
int noknots,nomaterials,nosides,newbound;
4346
int maxelementtype,maxedgenodes,elemedges,maxelemedges,edge,dosides;
4347
int **edgetable,sideind[MAXNODESD1],sideelemtype,allocated;
4348
int *indx;
4349
Real *arrange;
4350
4351
4352
newbound = 0;
4353
nomaterials = 0;
4354
maxelementtype = 0;
4355
noelements = data->noelements;
4356
4357
printf("FindEdges: Finding edges of bulk elements of type %d\n",material);
4358
maxelementtype = GetMaxElementType(data);
4359
4360
if(maxelementtype/100 > 4) {
4361
printf("FindEdges: Implemented only for 2D elements!\n");
4362
dosides = 0;
4363
return;
4364
}
4365
4366
if(maxelementtype/100 <= 2) maxedgenodes = 1;
4367
else if(maxelementtype/100 <= 4) maxedgenodes = 2;
4368
maxelemedges = maxelementtype/100;
4369
4370
edgetable = Imatrix(1,maxelemedges*nomaterials,0,maxedgenodes+1);
4371
for(i=1;i<=maxelemedges*nomaterials;i++)
4372
for(j=0;j<=maxedgenodes+1;j++)
4373
edgetable[i][j] = 0;
4374
4375
edge = 0;
4376
for(element=1;element<=noelements;element++) {
4377
if(data->material[element] != material) continue;
4378
4379
elemedges = data->elementtypes[element]/100;
4380
4381
for(side=0;side<elemedges;side++) {
4382
edge++;
4383
4384
GetElementSide(element,side,1,data,sideind,&sideelemtype);
4385
edgetable[edge][maxedgenodes] = element;
4386
edgetable[edge][maxedgenodes+1] = side;
4387
4388
if(maxedgenodes == 1)
4389
edgetable[edge][0] = sideind[0];
4390
else if(maxedgenodes == 2) {
4391
if(sideind[0] > sideind[1]) {
4392
edgetable[edge][0] = sideind[0];
4393
edgetable[edge][1] = sideind[1];
4394
}
4395
else {
4396
edgetable[edge][1] = sideind[0];
4397
edgetable[edge][0] = sideind[1];
4398
}
4399
}
4400
}
4401
}
4402
4403
noknots = edge;
4404
arrange = Rvector(1,noknots);
4405
for(i=1;i<=noknots;i++)
4406
arrange[i] = 0.0;
4407
for(i=1;i<=noknots;i++)
4408
arrange[i] = edgetable[i][0];
4409
indx = Ivector(1,noknots);
4410
4411
SortIndex(noknots,arrange,indx);
4412
4413
allocated = FALSE;
4414
4415
omstart:
4416
nosides = 0;
4417
4418
for(i=1;i<=noknots;i++) {
4419
identical = FALSE;
4420
if(maxedgenodes == 1) {
4421
for(j=i+1;j<=noknots && edgetable[indx[i]][0] == edgetable[indx[j]][0];j++)
4422
identical = TRUE;
4423
for(j=i-1;j>=1 && edgetable[indx[i]][0] == edgetable[indx[j]][0];j--)
4424
identical = TRUE;
4425
}
4426
else if(maxedgenodes == 2) {
4427
for(j=i+1;j<=noknots && edgetable[indx[i]][0] == edgetable[indx[j]][0];j++)
4428
if(edgetable[indx[i]][1] == edgetable[indx[j]][1])
4429
identical = TRUE;
4430
for(j=i-1;j>=1 && edgetable[indx[i]][0] == edgetable[indx[j]][0];j--)
4431
if(edgetable[indx[i]][1] == edgetable[indx[j]][1])
4432
identical = TRUE;
4433
}
4434
4435
if(identical) continue;
4436
nosides++;
4437
if(allocated) {
4438
bound[newbound].parent[nosides] = edgetable[indx[i]][maxedgenodes];
4439
bound[newbound].parent2[nosides] = 0;
4440
bound[newbound].side[nosides] = edgetable[indx[i]][maxedgenodes+1];
4441
bound[newbound].side2[nosides] = 0;
4442
bound[newbound].types[nosides] = sidetype;
4443
}
4444
}
4445
4446
if(!allocated) {
4447
for(j=0;j < MAXBOUNDARIES && bound[j].created;j++);
4448
newbound = j;
4449
AllocateBoundary(&bound[newbound],nosides);
4450
allocated = TRUE;
4451
if(info) printf("Created boundary %d of type %d and size %d for material %d\n",
4452
newbound,sidetype,nosides,material);
4453
goto omstart;
4454
}
4455
4456
free_Ivector(indx,1,noknots);
4457
free_Imatrix(edgetable,1,maxelemedges*nomaterials,0,maxedgenodes+1);
4458
}
4459
#endif
4460
4461
static int CompareIndexes(int elemtype,int *ind1,int *ind2)
4462
{
4463
int i,j,same,nosides,hits;
4464
4465
hits = 0;
4466
nosides = elemtype / 100;
4467
for(i=0;i<nosides;i++)
4468
for(j=0;j<nosides;j++)
4469
if(ind1[i] == ind2[j]) hits++;
4470
4471
same = (hits == nosides);
4472
return(same);
4473
}
4474
4475
4476
4477
int FindNewBoundaries(struct FemType *data,struct BoundaryType *bound,
4478
int *boundnodes,int suggesttype,int dimred,int info)
4479
{
4480
int i,j,side,identical,element,lowerdim,dim,minedge,maxedge;
4481
int noelements,noknots,nonodes,nosides,newbound;
4482
int sideind[MAXNODESD1],sideind0[MAXNODESD1],sideelemtype,sideelemtype0,allocated;
4483
int noboundnodes,sameside,newtype,elemtype;
4484
4485
newtype = 0;
4486
allocated = FALSE;
4487
dim = data->dim;
4488
if(dimred)
4489
lowerdim = dim - dimred;
4490
else
4491
lowerdim = dim-1;
4492
4493
noknots = data->noknots;
4494
noelements = data->noelements;
4495
noboundnodes = 0;
4496
newbound = 0;
4497
maxedge = 0;
4498
minedge = 0;
4499
4500
for(i=1;i<=noknots;i++)
4501
if(boundnodes[i]) noboundnodes++;
4502
if(!noboundnodes) {
4503
printf("FindNewBoundaries: no nonzero entries in boundnodes vector!\n");
4504
return(1);
4505
}
4506
else {
4507
if(info) printf("There are %d nonzero entries in boundnodes vector!\n",noboundnodes);
4508
}
4509
4510
omstart:
4511
4512
nosides = 0;
4513
for(element=1;element<=noelements;element++) {
4514
4515
elemtype = data->elementtypes[element];
4516
if(dim == 1) {
4517
minedge = 0;
4518
maxedge = elemtype/100 -1;
4519
}
4520
else if(dim == 2) {
4521
if(lowerdim == 1) {
4522
minedge = 0;
4523
maxedge = elemtype/100 -1;
4524
}
4525
else if(lowerdim == 0) {
4526
minedge = elemtype/100;
4527
maxedge = minedge + 1;
4528
}
4529
}
4530
else if(dim == 3) {
4531
if(lowerdim == 2) {
4532
minedge = 0;
4533
if(elemtype/100 == 5) maxedge = 3;
4534
else if(elemtype/100 == 6 || elemtype/100 == 7) maxedge = 4;
4535
else if(elemtype/100 == 8) maxedge = 5;
4536
}
4537
else if(lowerdim == 1) {
4538
if(elemtype/100 == 8) {
4539
minedge = 6;
4540
maxedge = 17;
4541
}
4542
else if(elemtype/100 == 5) {
4543
minedge = 4;
4544
maxedge = 9;
4545
}
4546
else
4547
printf("FindNewBoundaries: not implemented for all 3d boundaries\n");
4548
}
4549
else if(lowerdim == 0) {
4550
if(elemtype/100 == 8) {
4551
minedge = 18;
4552
maxedge = 25;
4553
}
4554
}
4555
}
4556
4557
for(side=minedge;side<=maxedge;side++) {
4558
4559
GetElementSide(element,side,1,data,sideind,&sideelemtype);
4560
4561
nonodes = sideelemtype % 100;
4562
identical = TRUE;
4563
for(i=0;i<nonodes;i++)
4564
if(!boundnodes[sideind[i]]) identical = FALSE;
4565
4566
if(!identical) continue;
4567
nosides++;
4568
4569
if(allocated) {
4570
for(i=1;i<nosides;i++) {
4571
if(bound[newbound].parent2[i]) continue;
4572
4573
GetElementSide(bound[newbound].parent[i],bound[newbound].side[i],
4574
1,data,sideind0,&sideelemtype0);
4575
if(sideelemtype0 != sideelemtype) continue;
4576
sameside = CompareIndexes(sideelemtype,sideind0,sideind);
4577
if(sameside) {
4578
bound[newbound].parent2[i] = element;
4579
bound[newbound].side2[i] = side;
4580
nosides--;
4581
goto foundsameside;
4582
}
4583
}
4584
4585
bound[newbound].types[nosides] = newtype;
4586
bound[newbound].parent[nosides] = element;
4587
bound[newbound].side[nosides] = side;
4588
bound[newbound].types[nosides] = newtype;
4589
4590
foundsameside:
4591
continue;
4592
}
4593
}
4594
}
4595
4596
if(nosides) {
4597
if(!allocated) {
4598
newtype = suggesttype;
4599
for(j=0;j < MAXBOUNDARIES && bound[j].created;j++) {
4600
newbound = j;
4601
if(suggesttype) continue;
4602
for(i=1;i<=bound[j].nosides;i++)
4603
if(bound[j].types[i] > newtype) newtype = bound[j].types[i];
4604
}
4605
newbound++;
4606
if(!suggesttype) newtype++;
4607
4608
AllocateBoundary(&bound[newbound],nosides);
4609
allocated = TRUE;
4610
if(info) printf("Allocating for %d sides of boundary %d\n",nosides,newtype);
4611
goto omstart;
4612
}
4613
4614
bound[newbound].nosides = nosides;
4615
if(info) printf("Found %d sides of dim %d to define boundary %d\n",nosides,lowerdim,newtype);
4616
4617
for(i=1;i<=nosides;i++) {
4618
if(j = bound[newbound].parent2[i]) {
4619
if(bound[newbound].parent[i] > bound[newbound].parent2[i]) {
4620
bound[newbound].parent2[i] = bound[newbound].parent[i];
4621
bound[newbound].parent[i] = j;
4622
j = bound[newbound].side2[i];
4623
bound[newbound].side2[i] = bound[newbound].side[i];
4624
bound[newbound].side[i] = j;
4625
}
4626
}
4627
}
4628
}
4629
else {
4630
if(lowerdim == 0) {
4631
printf("The nodes do not form a boundary!\n");
4632
return(2);
4633
}
4634
else {
4635
lowerdim--;
4636
printf("The nodes do not form a boundary, trying with %d-dimensional elements.\n",lowerdim);
4637
goto omstart;
4638
}
4639
}
4640
4641
return(0);
4642
}
4643
4644
4645
4646
int FindBulkBoundary(struct FemType *data,int mat1,int mat2,
4647
int *boundnodes,int *noboundnodes,int info)
4648
{
4649
int i,j,k;
4650
int nonodes,maxnodes,minnodes,material;
4651
Real ds,xmin=0.0,xmax=0.0,ymin=0.0,ymax=0.0,zmin=0.0,zmax=0.0,eps;
4652
int *visited,elemdim,*ind;
4653
Real *anglesum,dx1,dx2,dy1,dy2,dz1,dz2,ds1,ds2,dotprod;
4654
4655
eps = 1.0e-4;
4656
*noboundnodes = 0;
4657
4658
if(mat1 < 1 && mat2 < 1) {
4659
printf("FindBulkBoundary: Either of the materials must be positive\n");
4660
return(1);
4661
}
4662
else if(mat1 < 1) {
4663
i = mat1;
4664
mat1 = mat2;
4665
mat2 = i;
4666
}
4667
if(info) printf("Finding nodes between bulk elements of material %d and %d\n",mat1,mat2);
4668
4669
visited = Ivector(1,data->noknots);
4670
for(i=1;i<=data->noknots;i++)
4671
visited[i] = 0;
4672
4673
for(i=1;i<=data->noknots;i++)
4674
boundnodes[i] = 0;
4675
4676
elemdim = 0;
4677
for(i=1;i<=data->noelements;i++) {
4678
material = data->material[i];
4679
if(material == mat1) {
4680
nonodes = data->elementtypes[i] % 100;
4681
k = data->elementtypes[i]/100;
4682
if(k > elemdim) elemdim = k;
4683
4684
for(j=0;j<nonodes;j++) {
4685
k = data->topology[i][j];
4686
visited[k] += 1;
4687
}
4688
}
4689
}
4690
maxnodes = minnodes = visited[1];
4691
for(i=1;i<=data->noknots;i++) {
4692
if(visited[i] > maxnodes) maxnodes = visited[i];
4693
if(visited[i] < minnodes) minnodes = visited[i];
4694
}
4695
4696
if(elemdim == 3 || elemdim == 4) {
4697
anglesum = Rvector(1, data->noknots);
4698
for(i=1;i<=data->noknots;i++)
4699
anglesum[i] = 0.0;
4700
4701
for(i=1;i<=data->noelements;i++) {
4702
material = data->material[i];
4703
if(material == mat1) {
4704
nonodes = data->elementtypes[i]/100;
4705
ind = data->topology[i];
4706
4707
if(nonodes == 3 || nonodes == 4) {
4708
for(k=0;k<nonodes;k++) {
4709
dx1 = data->x[ind[(k+1)%nonodes]] - data->x[ind[k]];
4710
dy1 = data->y[ind[(k+1)%nonodes]] - data->y[ind[k]];
4711
dz1 = data->z[ind[(k+1)%nonodes]] - data->z[ind[k]];
4712
dx2 = data->x[ind[(k+nonodes-1)%nonodes]] - data->x[ind[k]];
4713
dy2 = data->y[ind[(k+nonodes-1)%nonodes]] - data->y[ind[k]];
4714
dz2 = data->z[ind[(k+nonodes-1)%nonodes]] - data->z[ind[k]];
4715
ds1 = sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
4716
ds2 = sqrt(dx2*dx2+dy2*dy2+dz2*dz2);
4717
dotprod = dx1*dx2 + dy1*dy2 + dz1*dz2;
4718
4719
anglesum[ind[k]] += acos(dotprod / (ds1*ds2));
4720
}
4721
}
4722
4723
}
4724
}
4725
j = 0;
4726
for(i=1;i<=data->noknots;i++) {
4727
anglesum[i] /= 2.0 * FM_PI;
4728
if(anglesum[i] > 0.99) visited[i] = 0;
4729
if(anglesum[i] > 1.01) printf("FindBulkBoundary: surprisingly large angle %.3e in node %d\n",anglesum[i],i);
4730
if(visited[i]) j++;
4731
}
4732
if(0) printf("There are %d boundary node candidates\n",j);
4733
free_Rvector(anglesum,1,data->noknots);
4734
}
4735
4736
else {
4737
for(i=1;i<=data->noknots;i++)
4738
if(visited[i] == maxnodes) visited[i] = 0;
4739
4740
if(maxnodes < 2) {
4741
printf("FindBulkBoundary: Nodes must belong to more than %d elements.\n",maxnodes);
4742
return(2);
4743
}
4744
}
4745
4746
if(mat2 == 0) {
4747
for(i=1;i<=data->noelements;i++) {
4748
material = data->material[i];
4749
if(material == mat1) continue;
4750
4751
nonodes = data->elementtypes[i] % 100;
4752
for(j=0;j<nonodes;j++) {
4753
k = data->topology[i][j];
4754
boundnodes[k] += 1;
4755
}
4756
}
4757
for(k=1;k<=data->noknots;k++) {
4758
if(!visited[k])
4759
boundnodes[k] = 0;
4760
else if(visited[k] < boundnodes[k])
4761
boundnodes[k] = 0;
4762
else if(visited[k] + boundnodes[k] < maxnodes)
4763
boundnodes[k] = 1;
4764
else
4765
boundnodes[k] = 0;
4766
}
4767
}
4768
else if(mat2 == -10) {
4769
for(i=1;i<=data->noknots;i++)
4770
if(visited[i]) boundnodes[i] = 1;
4771
}
4772
else if(mat2 == -11 || mat2 == -12 || mat2 > 0) {
4773
for(i=1;i<=data->noelements;i++) {
4774
material = data->material[i];
4775
4776
if(material == mat1) continue;
4777
if(mat2 > 0 && material != mat2) continue;
4778
if(mat2 == -11 && material < mat1) continue;
4779
if(mat2 == -12 && material > mat1) continue;
4780
4781
nonodes = data->elementtypes[i]%100;
4782
for(j=0;j<nonodes;j++) {
4783
k = data->topology[i][j];
4784
if(visited[k]) boundnodes[k] = 1;
4785
}
4786
}
4787
}
4788
else if(mat2 >= -2*data->dim && mat2 <= -1) {
4789
4790
j = TRUE;
4791
for(i=1;i<=data->noknots;i++)
4792
if(visited[i]) {
4793
if(j) {
4794
xmax = xmin = data->x[i];
4795
ymax = ymin = data->y[i];
4796
zmax = zmin = data->z[i];
4797
j = FALSE;
4798
}
4799
else {
4800
if(data->x[i] > xmax) xmax = data->x[i];
4801
if(data->x[i] < xmin) xmin = data->x[i];
4802
if(data->y[i] > ymax) ymax = data->y[i];
4803
if(data->y[i] < ymin) ymin = data->y[i];
4804
if(data->z[i] > zmax) zmax = data->z[i];
4805
if(data->z[i] < zmin) zmin = data->z[i];
4806
}
4807
}
4808
4809
ds = (xmax-xmin)*(xmax-xmin) +
4810
(ymax-ymin)*(ymax-ymin) + (zmax-zmin)*(zmax-zmin);
4811
4812
ds = sqrt(ds);
4813
eps = 1.0e-5 * ds;
4814
4815
4816
for(i=1;i<=data->noknots;i++)
4817
if(visited[i] < maxnodes && visited[i]) {
4818
4819
if(data->dim == 1) {
4820
if(mat2 == -1 && fabs(data->x[i]-xmin) < eps) boundnodes[i] = 1;
4821
else if(mat2 == -2 && fabs(data->x[i]-xmax) < eps) boundnodes[i] = 1;
4822
}
4823
if(data->dim >= 2) {
4824
if(mat2 == -1 && (fabs(data->y[i]-ymin) < eps)) boundnodes[i] = 1;
4825
else if(mat2 == -3 && (fabs(data->y[i]-ymax) < eps)) boundnodes[i] = 1;
4826
else if(mat2 == -4 && (fabs(data->x[i]-xmin) < eps)) boundnodes[i] = 1;
4827
else if(mat2 == -2 && (fabs(data->x[i]-xmax) < eps)) boundnodes[i] = 1;
4828
}
4829
if(data->dim >= 3) {
4830
if(mat2 == -5 && fabs(data->z[i]-zmin) < eps) boundnodes[i] = 1;
4831
else if(mat2 == -6 && fabs(data->z[i]-zmax) < eps) boundnodes[i] = 1;
4832
}
4833
}
4834
4835
}
4836
else {
4837
printf("FindBulkBoundary: unknown option %d for finding a side\n",mat2);
4838
return(2);
4839
}
4840
4841
4842
*noboundnodes = 0;
4843
for(i=1;i<=data->noknots;i++)
4844
if(boundnodes[i]) *noboundnodes += 1;
4845
4846
if(info) printf("Located %d nodes at the interval between materials %d and %d\n",
4847
*noboundnodes,mat1,mat2);
4848
4849
free_Ivector(visited,1,data->noknots);
4850
return(0);
4851
}
4852
4853
4854
4855
int FindBoundaryBoundary(struct FemType *data,struct BoundaryType *bound,int mat1,int mat2,
4856
int *boundnodes,int *noboundnodes,int info)
4857
{
4858
int i,j,k,l;
4859
int hits,nonodes,nocorners,maxnodes,minnodes,elemtype,material,bounddim;
4860
Real ds,xmin=0.0,xmax=0.0,ymin=0.0,ymax=0.0,zmin=0.0,zmax=0.0;
4861
Real eps,dx1,dx2,dy1,dy2,dz1,dz2,ds1,ds2,dotprod;
4862
Real *anglesum=NULL;
4863
int *visited,sideind[MAXNODESD2],elemind[MAXNODESD2];
4864
4865
eps = 1.0e-4;
4866
*noboundnodes = 0;
4867
4868
if(mat1 < 1 && mat2 < 1) {
4869
printf("FindBoundaryBoundary: Either of the boundaries must be positive\n");
4870
return(1);
4871
}
4872
else if(mat1 < 1) {
4873
i = mat1;
4874
mat1 = mat2;
4875
mat2 = i;
4876
}
4877
if(info) printf("Finding nodes between boundary elements of type %d and %d\n",mat1,mat2);
4878
4879
visited = Ivector(1,data->noknots);
4880
for(i=1;i<=data->noknots;i++)
4881
visited[i] = 0;
4882
4883
for(i=1;i<=data->noknots;i++)
4884
boundnodes[i] = 0;
4885
4886
bounddim = 0;
4887
/* Set a tag to all nodes that are part of the other boundary */
4888
for(j=0;j < MAXBOUNDARIES;j++) {
4889
if(!bound[j].created) continue;
4890
for(i=1; i <= bound[j].nosides; i++) {
4891
4892
if(bound[j].types[i] == mat1) {
4893
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
4894
data,sideind,&elemtype);
4895
4896
nonodes = elemtype % 100;
4897
nocorners = elemtype / 100;
4898
4899
for(k=0;k<nocorners;k++)
4900
visited[sideind[k]] += 1;
4901
for(k=nocorners;k<nonodes;k++)
4902
visited[sideind[k]] -= 1;
4903
4904
if(nocorners == 3 || nocorners == 4) {
4905
if(bounddim < 2) {
4906
anglesum = Rvector(1, data->noknots);
4907
for(k=1;k<=data->noknots;k++)
4908
anglesum[k] = 0.0;
4909
bounddim = 2;
4910
}
4911
nonodes = nocorners;
4912
for(k=0;k<nonodes;k++) {
4913
dx1 = data->x[sideind[(k+1)%nonodes]] - data->x[sideind[k]];
4914
dy1 = data->y[sideind[(k+1)%nonodes]] - data->y[sideind[k]];
4915
dz1 = data->z[sideind[(k+1)%nonodes]] - data->z[sideind[k]];
4916
dx2 = data->x[sideind[(k+nonodes-1)%nonodes]] - data->x[sideind[k]];
4917
dy2 = data->y[sideind[(k+nonodes-1)%nonodes]] - data->y[sideind[k]];
4918
dz2 = data->z[sideind[(k+nonodes-1)%nonodes]] - data->z[sideind[k]];
4919
ds1 = sqrt(dx1*dx1+dy1*dy1+dz1*dz1);
4920
ds2 = sqrt(dx2*dx2+dy2*dy2+dz2*dz2);
4921
dotprod = dx1*dx2 + dy1*dy2 + dz1*dz2;
4922
4923
anglesum[sideind[k]] += acos(dotprod / (ds1*ds2));
4924
}
4925
}
4926
4927
}
4928
}
4929
}
4930
4931
maxnodes = minnodes = abs(visited[1]);
4932
for(i=1;i<=data->noknots;i++) {
4933
j = abs( visited[i] );
4934
maxnodes = MAX( j, maxnodes );
4935
minnodes = MIN( j, minnodes );
4936
}
4937
if(info) printf("There are from %d to %d hits per node\n",minnodes,maxnodes);
4938
if(maxnodes < 2) {
4939
printf("FindBulkBoundary: Nodes must belong to more than %d elements.\n",maxnodes);
4940
return(2);
4941
}
4942
4943
if(bounddim == 2) {
4944
/* For corner nodes eliminate the ones with full angle */
4945
for(i=1;i<=data->noknots;i++) {
4946
anglesum[i] /= 2.0 * FM_PI;
4947
if(anglesum[i] > 0.99) visited[i] = 0;
4948
if(anglesum[i] > 1.01) printf("FindBulkBoundary: surprisingly large angle %.3e in node %d\n",anglesum[i],i);
4949
}
4950
free_Rvector(anglesum,1,data->noknots);
4951
4952
/* For higher order nodes eliminate the ones with more than one hits */
4953
k = 0;
4954
for(i=1;i<=data->noknots;i++) {
4955
if(visited[i] == -1)
4956
visited[i] = 1;
4957
else if(visited[i] < -1) {
4958
k++;
4959
visited[i] = 0;
4960
}
4961
}
4962
if(k && info) printf("Removed %d potential higher order side nodes from the list.\n",k);
4963
}
4964
4965
if(bounddim == 1) {
4966
if(visited[i] == maxnodes || visited[i] < 0) visited[i] = 0;
4967
}
4968
4969
/* Neighbour to anything */
4970
if(mat2 == 0) {
4971
for(k=1;k<=data->noknots;k++)
4972
if(visited[k])
4973
boundnodes[k] = 1;
4974
}
4975
/* Neighbour to other BCs */
4976
else if(mat2 == -11 || mat2 == -12 || mat2 == -10 || mat2 > 0) {
4977
for(j=0;j < MAXBOUNDARIES;j++) {
4978
if(!bound[j].created) continue;
4979
for(i=1; i <= bound[j].nosides; i++) {
4980
4981
material = bound[j].types[i];
4982
4983
if(material == mat1) continue;
4984
if(mat2 > 0 && material != mat2) continue;
4985
if(mat2 == -11 && material < mat1) continue;
4986
if(mat2 == -12 && material > mat1) continue;
4987
4988
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
4989
data,sideind,&elemtype);
4990
nonodes = elemtype%100;
4991
for(k=0;k<nonodes;k++) {
4992
l = sideind[k];
4993
if(visited[l]) boundnodes[l] = 1;
4994
}
4995
}
4996
}
4997
}
4998
4999
/* Neighbour to major coordinate directions */
5000
else if(mat2 >= -2*data->dim && mat2 <= -1) {
5001
5002
for(j=0;j < MAXBOUNDARIES;j++) {
5003
if(!bound[j].created) continue;
5004
for(i=1; i <= bound[j].nosides; i++) {
5005
5006
material = bound[j].types[i];
5007
if(material != mat1) continue;
5008
5009
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
5010
data,sideind,&elemtype);
5011
nonodes = elemtype%100;
5012
5013
hits = 0;
5014
for(k=0;k<nonodes;k++) {
5015
l = sideind[k];
5016
if(visited[l] < maxnodes) hits++;
5017
}
5018
if(!hits) continue;
5019
5020
l = sideind[0];
5021
xmax = xmin = data->x[l];
5022
ymax = ymin = data->y[l];
5023
zmax = zmin = data->z[l];
5024
5025
for(k=1;k<nonodes;k++) {
5026
l = sideind[k];
5027
if(data->x[l] > xmax) xmax = data->x[l];
5028
if(data->x[l] < xmin) xmin = data->x[l];
5029
if(data->y[l] > ymax) ymax = data->y[l];
5030
if(data->y[l] < ymin) ymin = data->y[l];
5031
if(data->z[l] > zmax) zmax = data->z[l];
5032
if(data->z[l] < zmin) zmin = data->z[l];
5033
}
5034
5035
ds = (xmax-xmin)*(xmax-xmin) +
5036
(ymax-ymin)*(ymax-ymin) + (zmax-zmin)*(zmax-zmin);
5037
ds = sqrt(ds);
5038
eps = 1.0e-3 * ds;
5039
5040
for(k=0;k<nonodes;k++) {
5041
elemind[k] = 0;
5042
l = sideind[k];
5043
if(!visited[l]) continue;
5044
5045
if(data->dim == 1) {
5046
if(mat2 == -1 && fabs(data->x[l]-xmin) < eps) boundnodes[l] = 1;
5047
else if(mat2 == -2 && fabs(data->x[l]-xmax) < eps) boundnodes[l] = 1;
5048
}
5049
if(data->dim >= 2) {
5050
if(mat2 == -1 && (fabs(data->y[l]-ymin) < eps)) elemind[l] = 1;
5051
else if(mat2 == -3 && (fabs(data->y[l]-ymax) < eps)) elemind[l] = 1;
5052
else if(mat2 == -4 && (fabs(data->x[l]-xmin) < eps)) elemind[l] = 1;
5053
else if(mat2 == -2 && (fabs(data->x[l]-xmax) < eps)) elemind[l] = 1;
5054
}
5055
if(data->dim >= 3) {
5056
if(mat2 == -5 && fabs(data->z[l]-zmin) < eps) elemind[l] = 1;
5057
else if(mat2 == -6 && fabs(data->z[l]-zmax) < eps) elemind[l] = 1;
5058
}
5059
}
5060
5061
if(data->dim > 1) {
5062
hits = 0;
5063
for(k=0;k<nonodes;k++)
5064
hits += elemind[k];
5065
5066
if(hits > 1) for(k=0;k<nonodes;k++)
5067
if(elemind[k]) boundnodes[sideind[k]] = 1;
5068
}
5069
}
5070
}
5071
}
5072
else {
5073
printf("FindBoundaryBoundary: unknown option %d for finding a side\n",mat2);
5074
return(2);
5075
}
5076
5077
*noboundnodes = 0;
5078
for(i=1;i<=data->noknots;i++)
5079
if(boundnodes[i]) *noboundnodes += 1;
5080
5081
if(info) printf("Located %d nodes at the interval between boundaries %d and %d\n",
5082
*noboundnodes,mat1,mat2);
5083
5084
free_Ivector(visited,1,data->noknots);
5085
return(0);
5086
}
5087
5088
5089
5090
int IncreaseElementOrder(struct FemType *data,int info)
5091
{
5092
int i,j,side,element,maxcon,con,newknots,ind,ind2;
5093
int noelements,noknots,nonodes,maxnodes,maxelemtype,hit,node;
5094
int elemtype,stat;
5095
int **newnodetable=NULL,inds[2],**newtopo=NULL;
5096
Real *newx=NULL,*newy=NULL,*newz=NULL;
5097
5098
if(info) printf("Trying to increase the element order of current elements\n");
5099
5100
CreateNodalGraph(data,FALSE,info);
5101
5102
noknots = data->noknots;
5103
noelements = data->noelements;
5104
maxcon = data->nodalmaxconnections;
5105
maxnodes = 0;
5106
5107
newnodetable = Imatrix(0,maxcon-1,1,noknots);
5108
for(i=1;i<=noknots;i++)
5109
for(j=0;j<maxcon;j++)
5110
newnodetable[j][i] = 0;
5111
5112
newknots = 0;
5113
for(i=1;i<=noknots;i++) {
5114
for(j=0;j<maxcon;j++) {
5115
con = data->nodalgraph[j][i];
5116
if(con > i) {
5117
newknots++;
5118
newnodetable[j][i] = noknots + newknots;
5119
}
5120
}
5121
}
5122
5123
if(info) printf("There will be %d new nodes in the elements\n",newknots);
5124
5125
newx = Rvector(1,noknots+newknots);
5126
newy = Rvector(1,noknots+newknots);
5127
newz = Rvector(1,noknots+newknots);
5128
5129
5130
for(i=1;i<=noknots;i++) {
5131
newx[i] = data->x[i];
5132
newy[i] = data->y[i];
5133
newz[i] = data->z[i];
5134
}
5135
for(i=1;i<=noknots;i++) {
5136
for(j=0;j<maxcon;j++) {
5137
con = data->nodalgraph[j][i];
5138
ind = newnodetable[j][i];
5139
if(con && ind) {
5140
newx[ind] = 0.5*(data->x[i] + data->x[con]);
5141
newy[ind] = 0.5*(data->y[i] + data->y[con]);
5142
newz[ind] = 0.5*(data->z[i] + data->z[con]);
5143
}
5144
}
5145
}
5146
5147
5148
maxelemtype = GetMaxElementType(data);
5149
5150
if(maxelemtype <= 303)
5151
maxnodes = 6;
5152
else if(maxelemtype == 404)
5153
maxnodes = 8;
5154
else if(maxelemtype == 504)
5155
maxnodes = 10;
5156
else if(maxelemtype == 605)
5157
maxnodes = 13;
5158
else if(maxelemtype == 706)
5159
maxnodes = 15;
5160
else if(maxelemtype == 808)
5161
maxnodes = 20;
5162
else {
5163
printf("Not implemented for elementtype %d\n",maxelemtype);
5164
bigerror("IncreaseElementOrder: Cannot continue the subroutine");
5165
}
5166
5167
if(info) printf("New leading elementtype is %d\n",100*(maxelemtype/100)+maxnodes);
5168
5169
newtopo = Imatrix(1,noelements,0,maxnodes-1);
5170
5171
for(element=1;element<=noelements;element++) {
5172
elemtype = data->elementtypes[element];
5173
for(i=0;i<elemtype%100;i++)
5174
newtopo[element][i] = data->topology[element][i];
5175
}
5176
5177
5178
for(element=1;element<=data->noelements;element++) {
5179
elemtype = data->elementtypes[element];
5180
5181
nonodes = data->elementtypes[element] % 100;
5182
for(side=0;;side++) {
5183
hit = GetElementGraph(element,side,data,inds);
5184
5185
if(!hit) break;
5186
if(inds[0] > inds[1]) {
5187
ind = inds[1];
5188
ind2 = inds[0];
5189
}
5190
else {
5191
ind = inds[0];
5192
ind2 = inds[1];
5193
}
5194
for(j=0;j<maxcon;j++) {
5195
con = data->nodalgraph[j][ind];
5196
5197
if(con == ind2) {
5198
node = newnodetable[j][ind];
5199
newtopo[element][nonodes+side] = node;
5200
}
5201
}
5202
}
5203
5204
elemtype = 100*(elemtype/100)+nonodes+side;
5205
data->elementtypes[element] = elemtype;
5206
}
5207
5208
stat = DestroyNodalGraph(data,info);
5209
5210
free_Rvector(data->x,1,data->noknots);
5211
free_Rvector(data->y,1,data->noknots);
5212
free_Rvector(data->z,1,data->noknots);
5213
free_Imatrix(data->topology,1,data->noelements,0,data->maxnodes);
5214
free_Imatrix(newnodetable,0,maxcon-1,1,noknots);
5215
5216
data->x = newx;
5217
data->y = newy;
5218
data->z = newz;
5219
data->topology = newtopo;
5220
5221
data->noknots += newknots;
5222
data->maxnodes = maxnodes;
5223
5224
if(info) printf("Increased the element order from 1 to 2\n");
5225
5226
return(0);
5227
}
5228
5229
5230
5231
static void CylindricalCoordinateTransformation(struct FemType *data,Real r1,Real r2,
5232
int rectangle)
5233
{
5234
int i,j,j2,ind1,ind2,nonodes1;
5235
Real x,y,r,f,z,q,x2,y2,z2,dx,dy,dz,eps,mult;
5236
int hits,trials,tests;
5237
int candidates,*candidatelist=NULL,*indx=NULL;
5238
5239
if(rectangle) {
5240
printf("Rectangular geometry with r1=%.4lg for %d nodes.\n",
5241
r1,data->noknots);
5242
}
5243
else {
5244
printf("Cylindrical geometry with r1=%.4lg r2=%.4lg for %d nodes.\n",
5245
r1,r2,data->noknots);
5246
}
5247
5248
5249
for(i=1;i<=data->noknots;i++) {
5250
r = data->x[i];
5251
z = data->y[i];
5252
f = data->z[i];
5253
5254
data->z[i] = z;
5255
5256
if(r >= r2) {
5257
data->x[i] = cos(f)*r;
5258
data->y[i] = sin(f)*r;
5259
}
5260
else if(r <= r2) {
5261
5262
mult = r/r1;
5263
5264
if(r > r1) {
5265
q = (r-r1)/(r2-r1);
5266
r = r1;
5267
}
5268
else {
5269
q = -1.0;
5270
}
5271
5272
if(f <= 0.25*FM_PI) {
5273
data->x[i] = r;
5274
data->y[i] = r1*4*(f-0.00*FM_PI)/FM_PI;
5275
}
5276
else if(f <= 0.75*FM_PI) {
5277
data->y[i] = r;
5278
data->x[i] = -r1*4*(f-0.5*FM_PI)/FM_PI;
5279
}
5280
else if(f <= 1.25*FM_PI) {
5281
data->x[i] = -r;
5282
data->y[i] = -r1*4*(f-1.0*FM_PI)/FM_PI;
5283
}
5284
else if(f <= 1.75*FM_PI){
5285
data->y[i] = -r;
5286
data->x[i] = r1*4*(f-1.5*FM_PI)/FM_PI;
5287
}
5288
else {
5289
data->x[i] = r;
5290
data->y[i] = r1*4*(f-2.0*FM_PI)/FM_PI;
5291
}
5292
5293
if(!rectangle && q > 0.0) {
5294
data->x[i] = (1-q)*data->x[i] + q*cos(f)*r2;
5295
data->y[i] = (1-q)*data->y[i] + q*sin(f)*r2;
5296
}
5297
else if(rectangle && mult > 1.0) {
5298
data->y[i] *= mult;
5299
data->x[i] *= mult;
5300
}
5301
} /* r <= r2 */
5302
}
5303
5304
eps = 1.0e-3 * data->minsize;
5305
5306
candidates = 0;
5307
candidatelist = Ivector(1,data->noknots);
5308
indx = Ivector(1,data->noknots);
5309
5310
for(i=1;i<=data->noknots;i++)
5311
indx[i] = 0;
5312
5313
for(j=1;j<=data->noelements;j++) {
5314
nonodes1 = data->elementtypes[j]%100;
5315
for(i=0;i<nonodes1;i++) {
5316
ind2 = data->topology[j][i];
5317
indx[ind2] = ind2;
5318
}
5319
}
5320
5321
5322
for(i=1;i<=data->noknots;i++) {
5323
if(!indx[i]) continue;
5324
5325
x = data->x[i];
5326
y = data->y[i];
5327
if(fabs(y) > r1+eps) continue;
5328
if((fabs(x) > r1+eps) && (fabs(y) > eps) ) continue;
5329
if((fabs(x) > eps) && (fabs(y) > eps) &&
5330
(fabs(fabs(x)-r1) > eps) && (fabs(fabs(y)-r1) > eps)) continue;
5331
5332
candidates++;
5333
candidatelist[candidates] = i;
5334
}
5335
printf("%d/%d candidates for duplicate nodes.\n",candidates,data->noknots);
5336
5337
hits = tests = trials = 0;
5338
for(j=1;j<=candidates;j++) {
5339
ind1 = indx[candidatelist[j]];
5340
x = data->x[ind1];
5341
y = data->y[ind1];
5342
z = data->z[ind1];
5343
5344
for(j2=j+1;j2<=candidates;j2++) {
5345
ind2 = indx[candidatelist[j2]];
5346
5347
x2 = data->x[ind2];
5348
y2 = data->y[ind2];
5349
z2 = data->z[ind2];
5350
5351
dx = x-x2;
5352
dy = y-y2;
5353
dz = z-z2;
5354
5355
tests++;
5356
if(dx*dx + dy*dy + dz*dz < eps*eps) {
5357
if(ind2 != ind1) {
5358
indx[candidatelist[j2]] = ind1;
5359
hits++;
5360
}
5361
}
5362
}
5363
}
5364
printf("Found %d double nodes in %d tests.\n",hits,tests);
5365
5366
for(j=1;j<=data->noelements;j++) {
5367
nonodes1 = data->elementtypes[j]%100;
5368
for(i=0;i<nonodes1;i++) {
5369
ind2 = data->topology[j][i];
5370
if(ind2 != indx[ind2]) {
5371
trials++;
5372
data->topology[j][i] = indx[ind2];
5373
}
5374
}
5375
}
5376
free_Ivector(indx,1,data->noknots);
5377
free_Ivector(candidatelist,1,data->noknots);
5378
5379
printf("Eliminated %d nodes from topology.\n",trials);
5380
}
5381
5382
5383
static void CylindricalCoordinateImprove(struct FemType *data,Real factor,
5384
Real r1,Real r2)
5385
{
5386
int i;
5387
Real x,y,r,q,q2,c,cmin,cmax,eps;
5388
5389
printf("Cylindrical coordinate for r1=%.4lg and r2=%.4lg.\n",r1,r2);
5390
5391
eps = 1.0e-10;
5392
5393
cmin = 1.0/(3.0-sqrt(3.));
5394
cmax = 1.0;
5395
5396
if(factor > 1.0) factor=1.0;
5397
else if(factor < 0.0) factor=0.0;
5398
5399
c = cmin+(cmax-cmin)*factor;
5400
5401
if(fabs(c-1.0) < eps) return;
5402
5403
printf("Improving cylindrical mesh quality r1=%.4lg, r2=%.4lg and c=%.4lg\n",r1,r2,c);
5404
5405
for(i=1;i<=data->noknots;i++) {
5406
x = data->x[i];
5407
y = data->y[i];
5408
5409
r = sqrt(x*x+y*y);
5410
if(r >= r2) continue;
5411
if(r < eps) continue;
5412
5413
if(fabs(x) <= r1+eps && fabs(y) <= r1+eps) {
5414
if(fabs(x) < fabs(y)) {
5415
q = fabs(x/y);
5416
data->x[i] = (c*q+(1.-q))*x;
5417
data->y[i] = (c*q+(1.-q))*y;
5418
}
5419
else {
5420
q = fabs(y/x);
5421
data->x[i] = (c*q+(1.-q))*x;
5422
data->y[i] = (c*q+(1.-q))*y;
5423
}
5424
}
5425
else {
5426
if(fabs(x) < fabs(y)) {
5427
q = fabs(x/y);
5428
q2 = (fabs(y)-r1)/(r2*fabs(y/r)-r1);
5429
data->x[i] = (c*q+(1.-q)) *x*(1-q2) + q2*x;
5430
data->y[i] = (c*q+(1.-q)) *(1-q2)*y + q2*y;
5431
}
5432
else {
5433
q = fabs(y/x);
5434
q2 = (fabs(x)-r1)/(r2*fabs(x/r)-r1);
5435
data->x[i] = (c*q+(1.-q))*(1-q2)*x + q2*x;
5436
data->y[i] = (c*q+(1.-q))*y*(1-q2) + q2*y;
5437
}
5438
}
5439
}
5440
}
5441
5442
5443
void CylindricalCoordinateCurve(struct FemType *data,
5444
Real zet,Real rad,Real angle)
5445
{
5446
int i;
5447
Real x,y,z;
5448
Real z0,z1,f,f0,z2,x2,r0;
5449
5450
printf("Cylindrical coordinate curve, zet=%.3lg rad=%.3lg angle=%.3lg\n",
5451
zet,rad,angle);
5452
5453
r0 = rad;
5454
f0 = FM_PI*(angle/180.);
5455
z0 = zet;
5456
z1 = z0+r0*f0;
5457
5458
for(i=1;i<=data->noknots;i++) {
5459
5460
if(data->dim == 2) {
5461
z = data->x[i];
5462
x = data->y[i];
5463
}
5464
else {
5465
x = data->x[i];
5466
y = data->y[i];
5467
z = data->z[i];
5468
}
5469
5470
if(z <= z0) continue;
5471
5472
if(z >= z1) {
5473
z2 = z0 + sin(f0)*(r0+x) + cos(f0)*(z-z1);
5474
x2 = (cos(f0)-1.0)*r0 + cos(f0)*x - sin(f0)*(z-z1);
5475
}
5476
else {
5477
f = (z-z0)/r0;
5478
z2 = z0 + sin(f)*(r0+x);
5479
x2 = (cos(f)-1.0)*r0 + cos(f)*x;
5480
}
5481
5482
if( data->dim == 2) {
5483
data->x[i] = z2;
5484
data->y[i] = x2;
5485
}
5486
else {
5487
data->z[i] = z2;
5488
data->x[i] = x2;
5489
}
5490
5491
}
5492
}
5493
5494
5495
void SeparateCartesianBoundaries(struct FemType *data,struct BoundaryType *bound,int info)
5496
{
5497
int i,j,k,l,type,maxtype,addtype,elemsides,totsides,used,hit;
5498
int sideelemtype,sideind[MAXBOUNDARIES];
5499
Real x,y,z,sx,sy,sz,sxx,syy,szz,dx,dy,dz;
5500
Real bclim[MAXBOUNDARIES];
5501
int bc[MAXBOUNDARIES],bcdim[MAXBOUNDARIES];
5502
Real eps=1.0e-4;
5503
5504
maxtype = 0;
5505
totsides = 0;
5506
for(j=0;j<MAXBOUNDARIES;j++) {
5507
if(!bound[j].created) continue;
5508
if(!bound[j].nosides) continue;
5509
5510
for(i=1;i<=bound[j].nosides;i++) {
5511
totsides++;
5512
for(k=1;k<=bound[j].nosides;k++)
5513
if(maxtype < bound[j].types[k]) maxtype = bound[j].types[k];
5514
}
5515
}
5516
5517
if(info) {
5518
printf("Maximum boundary type is %d\n",maxtype);
5519
printf("Number of boundaries is %d\n",totsides);
5520
}
5521
addtype = maxtype;
5522
5523
for(type=1;type<=maxtype;type++) {
5524
5525
for(i=0;i<MAXBOUNDARIES;i++)
5526
bclim[i] = 0.0;
5527
for(i=0;i<MAXBOUNDARIES;i++)
5528
bc[i] = bcdim[i] = 0;
5529
used = FALSE;
5530
5531
for(j=0;j<MAXBOUNDARIES;j++) {
5532
5533
if(!bound[j].created) continue;
5534
if(!bound[j].nosides) continue;
5535
5536
for(k=1;k<=bound[j].nosides;k++) {
5537
5538
if(bound[j].types[k] != type) continue;
5539
GetElementSide(bound[j].parent[k],bound[j].side[k],bound[j].normal[k],
5540
data,sideind,&sideelemtype);
5541
5542
sx = sy = sz = 0.0;
5543
sxx = syy = szz = 0.0;
5544
elemsides = sideelemtype%100;
5545
5546
/* Compute the variance within each axis */
5547
for(l=0;l<elemsides;l++) {
5548
x = data->x[sideind[l]];
5549
y = data->y[sideind[l]];
5550
z = data->z[sideind[l]];
5551
sx += x;
5552
sy += y;
5553
sz += z;
5554
sxx += x*x;
5555
syy += y*y;
5556
szz += z*z;
5557
}
5558
sx /= elemsides;
5559
sy /= elemsides;
5560
sz /= elemsides;
5561
sxx /= elemsides;
5562
syy /= elemsides;
5563
szz /= elemsides;
5564
dx = sqrt(sxx-sx*sx);
5565
dy = sqrt(syy-sy*sy);
5566
dz = sqrt(szz-sz*sz);
5567
5568
if(sideelemtype < 300 && dz < eps) {
5569
5570
if(dx < eps * dy) {
5571
hit = FALSE;
5572
for(i=0;i<MAXBOUNDARIES && bcdim[i];i++) {
5573
if(bcdim[i] == 1 && fabs(bclim[i]-sx) < eps*fabs(dy)) {
5574
bound[j].types[k] = bc[i];
5575
hit = TRUE;
5576
break;
5577
}
5578
}
5579
5580
if(!hit) {
5581
if(used) {
5582
addtype++;
5583
printf("Adding new BC %d in Y-direction\n",addtype);
5584
bc[i] = addtype;
5585
bound[j].types[k] = bc[i];
5586
}
5587
else {
5588
bc[i] = bound[j].types[k];
5589
}
5590
bcdim[i] = 1;
5591
bclim[i] = sx;
5592
used = TRUE;
5593
}
5594
}
5595
5596
if(dy < eps * dx) {
5597
hit = FALSE;
5598
for(i=0;i<MAXBOUNDARIES && bcdim[i];i++) {
5599
if(bcdim[i] == 2 && fabs(bclim[i]-sy) < eps*fabs(dx)) {
5600
bound[j].types[k] = bc[i];
5601
hit = TRUE;
5602
break;
5603
}
5604
}
5605
if(!hit) {
5606
if(used) {
5607
addtype++;
5608
printf("Adding new BC %d in X-direction\n",addtype);
5609
bc[i] = addtype;
5610
bound[j].types[k] = bc[i];
5611
}
5612
else {
5613
bc[i] = bound[j].types[k];
5614
}
5615
bcdim[i] = 2;
5616
bclim[i] = sy;
5617
used = TRUE;
5618
}
5619
}
5620
}
5621
else {
5622
if(dx < eps*dy && dx < eps*dz) {
5623
}
5624
else if(dy < eps*dx && dy < eps*dz) {
5625
}
5626
}
5627
}
5628
}
5629
}
5630
}
5631
5632
5633
5634
5635
void SeparateMainaxisBoundaries(struct FemType *data,struct BoundaryType *bound)
5636
{
5637
int i,j,k,l,maxtype,addtype,elemsides;
5638
int sideelemtype,sideind[MAXNODESD1];
5639
int axistype[4],axishit[4],axissum,axismax,done;
5640
Real x,y,z,sx,sy,sz,sxx,syy,szz,dx,dy,dz;
5641
Real eps=1.0e-6;
5642
5643
maxtype = 0;
5644
addtype = 0;
5645
5646
for(j=0;j<data->noboundaries;j++) {
5647
5648
if(!bound[j].created) continue;
5649
if(!bound[j].nosides) continue;
5650
5651
for(i=1;i<=bound[j].nosides;i++) {
5652
for(k=1;k<=bound[j].nosides;k++)
5653
if(maxtype < bound[j].types[k]) maxtype = bound[j].types[k];
5654
}
5655
}
5656
printf("Maximum boundary type is %d\n",maxtype);
5657
5658
#if 0
5659
for(j=0;j<data->noboundaries;j++) {
5660
if(!bound[j].created) continue;
5661
if(!bound[j].nosides) continue;
5662
if(bound[j].type) {
5663
bound[j].types = Ivector(1,bound[j].nosides);
5664
for(k=1;k<=bound[j].nosides;k++)
5665
bound[j].types[k] = bound[j].type;
5666
bound[j].type = 0;
5667
}
5668
}
5669
#endif
5670
5671
for(j=0;j<data->noboundaries;j++) {
5672
if(!bound[j].created) continue;
5673
if(!bound[j].nosides) continue;
5674
5675
for(k=0;k<4;k++) axishit[k] = 0;
5676
5677
done = 0;
5678
5679
omstart:
5680
5681
for(k=1;k<=bound[j].nosides;k++) {
5682
5683
GetElementSide(bound[j].parent[k],bound[j].side[k],bound[j].normal[k],
5684
data,sideind,&sideelemtype);
5685
5686
sx = sy = sz = 0.0;
5687
sxx = syy = szz = 0.0;
5688
elemsides = sideelemtype%100;
5689
5690
/* Compute the variance within each axis */
5691
for(l=0;l<elemsides;l++) {
5692
x = data->x[sideind[l]];
5693
y = data->y[sideind[l]];
5694
z = data->z[sideind[l]];
5695
sx += x;
5696
sy += y;
5697
sz += z;
5698
sxx += x*x;
5699
syy += y*y;
5700
szz += z*z;
5701
}
5702
sx /= elemsides;
5703
sy /= elemsides;
5704
sz /= elemsides;
5705
sxx /= elemsides;
5706
syy /= elemsides;
5707
szz /= elemsides;
5708
dx = sqrt(sxx-sx*sx);
5709
dy = sqrt(syy-sy*sy);
5710
dz = sqrt(szz-sz*sz);
5711
5712
if(dx < eps*dy && dx < eps*dz) {
5713
if(sx > 0.0) {
5714
if(done) {
5715
if(axistype[0]) bound[j].types[k] = maxtype + axistype[0];
5716
}
5717
else
5718
axishit[0] += 1;
5719
}
5720
if(sx < 0.0) {
5721
if(done) {
5722
if(axistype[1]) bound[j].types[k] = maxtype + axistype[1];
5723
}
5724
else
5725
axishit[1] += 1;
5726
}
5727
}
5728
else if(dy < eps*dx && dy < eps*dz) {
5729
if(sy > 0.0) {
5730
if(done) {
5731
if(axistype[2]) bound[j].types[k] = maxtype + axistype[2];
5732
}
5733
else
5734
axishit[2] += 1;
5735
}
5736
if(sy < 0.0) {
5737
if(done) {
5738
if(axistype[3]) bound[j].types[k] = maxtype + axistype[3];
5739
}
5740
else
5741
axishit[3] += 1;
5742
}
5743
}
5744
}
5745
5746
/* All this is done to select the sidetype appropriately */
5747
if(!done) {
5748
axissum = 0;
5749
axismax = 0;
5750
5751
for(k=0;k<4;k++) {
5752
axissum += axishit[k];
5753
if(axishit[k]) addtype++;
5754
}
5755
5756
if(axissum) {
5757
for(k=0;k<4;k++) {
5758
axismax = 0;
5759
for(l=0;l<4;l++) {
5760
if(axishit[l] > axishit[axismax])
5761
axismax = l;
5762
}
5763
axistype[axismax] = k+1;
5764
axishit[axismax] = -(k+1);
5765
}
5766
5767
if(axissum == bound[j].nosides) {
5768
for(k=0;k<4;k++)
5769
axistype[k] -= 1;
5770
addtype--;
5771
}
5772
5773
if(addtype) {
5774
printf("Separating %d rectangular boundaries from boundary %d.\n",addtype,j);
5775
done = 1;
5776
goto omstart;
5777
}
5778
else done = 0;
5779
}
5780
}
5781
maxtype += addtype;
5782
}
5783
}
5784
5785
5786
void CreateKnotsExtruded(struct FemType *dataxy,struct BoundaryType *boundxy,
5787
struct GridType *grid,
5788
struct FemType *data,struct BoundaryType *bound,
5789
int info)
5790
/* Create mesh from 2D mesh either by extrusion or by rotation.
5791
Also create the additional boundaries using automated numbering. */
5792
{
5793
#define MAXNEWBC 200
5794
int i,j,k,l,m,n,knot0,knot1,knot2,elem0,size,kmax,noknots,origtype;
5795
int nonodes3d,nonodes2d,bclevel,bcset;
5796
int cellk,element,level,side,parent,parent2,layers,elemtype,material_too_large;
5797
int material,material2,ind1,ind2;
5798
int *indx=NULL,*topo=NULL;
5799
int sideelemtype,sideind[MAXNODESD1],sidetype,minsidetype,maxsidetype,cummaxsidetype,newbounds;
5800
int refmaterial1[MAXNEWBC],refmaterial2[MAXNEWBC],refsidetype[MAXNEWBC],indxlength;
5801
Real z,*newx=NULL,*newy=NULL,*newz=NULL,corder[3];
5802
Real meanx,meany;
5803
int layerbcoffset;
5804
int usenames;
5805
5806
if(grid->rotate)
5807
SetElementDivisionCylinder(grid,info);
5808
else if(grid->dimension == 3)
5809
SetElementDivisionExtruded(grid,info);
5810
else {
5811
printf("CreateKnotsExtruded: unknown option!\n");
5812
return;
5813
}
5814
5815
InitializeKnots(data);
5816
5817
data->dim = 3;
5818
5819
origtype = 0;
5820
for(i=1;i<=dataxy->noelements;i++)
5821
origtype = MAX( origtype, dataxy->elementtypes[i]);
5822
5823
if(origtype == 202)
5824
elemtype = 404;
5825
else if(origtype == 303)
5826
elemtype = 706;
5827
else if(origtype == 404)
5828
elemtype = 808;
5829
else if(origtype == 408)
5830
elemtype = 820;
5831
else if(origtype == 409)
5832
elemtype = 827;
5833
else {
5834
printf("CreateKnotsExtruded: not implemented for elementtypes %d!\n",origtype);
5835
return;
5836
}
5837
printf("Maximum elementtype %d extruded to type %d.\n",origtype,elemtype);
5838
5839
nonodes2d = origtype%100;
5840
data->maxnodes = nonodes3d = elemtype%100;
5841
if(nonodes3d <= 8)
5842
layers = 1;
5843
else
5844
layers = 2;
5845
5846
/* Initialize the 3D mesh structure */
5847
data->noknots = noknots = dataxy->noknots*(layers*grid->totzelems+1);
5848
data->noelements = dataxy->noelements * grid->totzelems;
5849
data->coordsystem = dataxy->coordsystem;
5850
data->numbering = dataxy->numbering;
5851
data->noboundaries = dataxy->noboundaries;
5852
data->maxsize = dataxy->maxsize;
5853
data->minsize = dataxy->minsize;
5854
data->partitionexist = FALSE;
5855
data->periodicexist = FALSE;
5856
data->nodeconnectexist = FALSE;
5857
data->elemconnectexist = FALSE;
5858
5859
usenames = dataxy->bodynamesexist || dataxy->boundarynamesexist;
5860
if( usenames ) {
5861
if( grid->zmaterialmapexists ) {
5862
printf("Cannot extrude names when there is a given material mapping!\n");
5863
usenames = FALSE;
5864
}
5865
else {
5866
if(info) printf("Trying to maintain entity names in extrusion\n");
5867
}
5868
}
5869
5870
5871
5872
maxsidetype = 0;
5873
5874
AllocateKnots(data);
5875
indxlength = MAX(data->noknots,data->noelements);
5876
indx = Ivector(0,indxlength);
5877
for(i=0;i<=indxlength;i++)
5878
indx[i] = 0;
5879
5880
newbounds = 0;
5881
if(grid->dimension == 3)
5882
newbounds = grid->zcells+1;
5883
else if(grid->rotate) {
5884
if(grid->rotateblocks < 4)
5885
newbounds = 4;
5886
if(grid->rotatecartesian)
5887
newbounds += grid->rotateblocks;
5888
}
5889
5890
/* Initialize the boundaries of the 3D mesh */
5891
for(j=0;j<data->noboundaries+newbounds;j++) {
5892
if(boundxy[j].created || j>=data->noboundaries) {
5893
bound[j] = boundxy[j];
5894
bound[j].created = TRUE;
5895
5896
size = bound[j].nosides = boundxy[j].nosides * grid->totzelems;
5897
if(j >= data->noboundaries) size = dataxy->noelements;
5898
5899
bound[j].coordsystem = COORD_CART3;
5900
bound[j].side = Ivector(1,size);
5901
bound[j].side2 = Ivector(1,size);
5902
bound[j].material = Ivector(1,size);
5903
bound[j].parent = Ivector(1,size);
5904
bound[j].parent2 = Ivector(1,size);
5905
bound[j].types = Ivector(1,size);
5906
bound[j].normal = Ivector(1,size);
5907
5908
for(i=1;i<=size;i++) {
5909
bound[j].types[i] = 0;
5910
bound[j].side[i] = 0;
5911
bound[j].side2[i] = 0;
5912
bound[j].parent[i] = 0;
5913
bound[j].parent2[i] = 0;
5914
bound[j].material[i] = 0;
5915
bound[j].normal[i] = 1;
5916
}
5917
bound[j].echain = FALSE;
5918
bound[j].ediscont = FALSE;
5919
}
5920
}
5921
if(info) printf("Allocated for %d new BC lists\n",j);
5922
5923
knot0 = 0;
5924
knot1 = layers*dataxy->noknots;
5925
if(layers == 2)
5926
knot2 = dataxy->noknots;
5927
else
5928
knot2 = 0;
5929
elem0 = 0;
5930
level = 0;
5931
material_too_large = 0;
5932
5933
/* Set the element topology of the extruded mesh */
5934
for(cellk=1;cellk <= grid->zcells ;cellk++) {
5935
5936
kmax = grid->zelems[cellk];
5937
5938
for(k=1;k<=kmax; k++) {
5939
5940
level++;
5941
5942
for(element=1;element <= dataxy->noelements;element++) {
5943
5944
origtype = dataxy->elementtypes[element];
5945
nonodes2d = origtype % 100;
5946
5947
if(origtype == 202)
5948
elemtype = 404;
5949
else if(origtype == 303)
5950
elemtype = 706;
5951
else if(origtype == 404)
5952
elemtype = 808;
5953
else if(origtype == 408)
5954
elemtype = 820;
5955
else if(origtype == 409)
5956
elemtype = 827;
5957
5958
if( grid->zmaterialmapexists ) {
5959
material = dataxy->material[element];
5960
if(material > grid->maxmaterial ) {
5961
material_too_large += 1;
5962
continue;
5963
}
5964
material = grid->zmaterialmap[cellk][material];
5965
if(material <= 0 ) continue;
5966
}
5967
else {
5968
if(dataxy->material[element] < grid->zfirstmaterial[cellk]) continue;
5969
if(dataxy->material[element] > grid->zlastmaterial[cellk]) continue;
5970
5971
if(grid->zmaterial[cellk])
5972
material = grid->zmaterial[cellk];
5973
else
5974
material = dataxy->material[element];
5975
}
5976
5977
if(grid->rotate) {
5978
meanx = 0.0;
5979
for(i=0;i<nonodes2d;i++)
5980
meanx += dataxy->x[dataxy->topology[element][i]];
5981
meanx = fabs(meanx/nonodes2d);
5982
}
5983
if(grid->rotate && meanx < 0.0) continue;
5984
if(grid->rotate && cellk%2==0 && meanx < grid->rotateradius1) continue;
5985
5986
elem0++;
5987
/* Vector telling the new element order. */
5988
indx[(level-1)*dataxy->noelements+element] = elem0;
5989
data->elementtypes[elem0] = elemtype;
5990
data->material[elem0] = material;
5991
5992
if(elemtype == 706) {
5993
for(i=0;i<3;i++) {
5994
data->topology[elem0][i] = dataxy->topology[element][i]+knot0;
5995
data->topology[elem0][i+3] = dataxy->topology[element][i]+knot1;
5996
}
5997
}
5998
else if(elemtype == 808) {
5999
for(i=0;i<4;i++) {
6000
data->topology[elem0][i] = dataxy->topology[element][i]+knot0;
6001
data->topology[elem0][i+4] = dataxy->topology[element][i]+knot1;
6002
}
6003
}
6004
if(elemtype == 820 || elemtype == 827) {
6005
for(i=0;i<4;i++) {
6006
data->topology[elem0][i] = dataxy->topology[element][i]+knot0;
6007
data->topology[elem0][i+4] = dataxy->topology[element][i]+knot1;
6008
data->topology[elem0][i+8] = dataxy->topology[element][i+4]+knot0;
6009
data->topology[elem0][i+12] = dataxy->topology[element][i]+knot2;
6010
data->topology[elem0][i+16] = dataxy->topology[element][i+4]+knot1;
6011
}
6012
}
6013
if(elemtype == 827) {
6014
for(i=0;i<4;i++)
6015
data->topology[elem0][20+i] = dataxy->topology[element][4+i]+knot2;
6016
data->topology[elem0][24] = dataxy->topology[element][8]+knot0;
6017
data->topology[elem0][25] = dataxy->topology[element][8]+knot1;
6018
data->topology[elem0][26] = dataxy->topology[element][8]+knot2;
6019
}
6020
else if(elemtype == 404) {
6021
data->topology[elem0][0] = dataxy->topology[element][0]+knot0;
6022
data->topology[elem0][1] = dataxy->topology[element][1]+knot0;
6023
data->topology[elem0][2] = dataxy->topology[element][1]+knot1;
6024
data->topology[elem0][3] = dataxy->topology[element][0]+knot1;
6025
}
6026
}
6027
knot0 += layers*dataxy->noknots;
6028
knot1 += layers*dataxy->noknots;
6029
knot2 += layers*dataxy->noknots;
6030
}
6031
}
6032
data->noelements = elem0;
6033
printf("Extruded mesh has %d elements in %d levels.\n",elem0,level);
6034
printf("Simple extrusion would have %d elements\n",level*dataxy->noelements);
6035
6036
if( material_too_large > 0 ) {
6037
printf("Material index exceeded %d the size of material permutation table (%d)!\n",
6038
material_too_large,grid->maxmaterial);
6039
printf("Give the max material with > Extruded Max Material < , if needed\n");
6040
}
6041
6042
6043
if(elem0 == 0) bigerror("No use to continue with zero elements!");
6044
6045
/* Set the nodal coordinates of the extruded mesh. */
6046
knot0 = 0;
6047
for(cellk=1;cellk <= grid->zcells ;cellk++) {
6048
6049
if(cellk == 1) k=0;
6050
else k=1;
6051
for(;k<=grid->zelems[cellk]; k++) {
6052
6053
if(grid->zlinear[cellk]) {
6054
z = grid->z[cellk-1] + k*grid->dz[cellk];
6055
}
6056
else if(grid->zexpand[cellk] > 0.0) {
6057
z = grid->z[cellk-1] + grid->dz[cellk] *
6058
(1.- pow(grid->zratios[cellk],(Real)(k))) / (1.-grid->zratios[cellk]);
6059
}
6060
else if(grid->zelems[cellk] <= 2) {
6061
z = grid->z[cellk-1] + k*grid->dz[cellk];
6062
}
6063
else {
6064
if((k<=grid->zelems[cellk]/2)) {
6065
z = grid->z[cellk-1] + grid->dz[cellk] *
6066
(1.- pow(grid->zratios[cellk],(Real)(k))) / (1.-grid->zratios[cellk]);
6067
}
6068
else {
6069
z = grid->z[cellk] - grid->dz[cellk] *
6070
(1.- pow(grid->zratios[cellk],(Real)(grid->zelems[cellk]-k))) / (1.-grid->zratios[cellk]);
6071
}
6072
}
6073
6074
for(i=1;i <= dataxy->noknots;i++) {
6075
data->x[i+knot0] = dataxy->x[i];
6076
data->y[i+knot0] = dataxy->y[i];
6077
data->z[i+knot0] = z;
6078
}
6079
knot0 += layers * dataxy->noknots;
6080
}
6081
}
6082
6083
6084
/* Set the coordinates for the middle nodes in case
6085
of quadratic elements. */
6086
if(elemtype == 820 || elemtype == 827) {
6087
for(element=1;element <= data->noelements;element++) {
6088
topo = data->topology[element];
6089
for(i=0;i<4;i++) {
6090
data->x[topo[i+12]] = 0.5*(data->x[topo[i]]+data->x[topo[i+4]]);
6091
data->y[topo[i+12]] = 0.5*(data->y[topo[i]]+data->y[topo[i+4]]);
6092
data->z[topo[i+12]] = 0.5*(data->z[topo[i]]+data->z[topo[i+4]]);
6093
}
6094
if(elemtype == 827) {
6095
for(i=0;i<4;i++) {
6096
data->x[topo[i+20]] = 0.5*(data->x[topo[12+i]]+data->x[topo[12+(i+1)%4]]);
6097
data->y[topo[i+20]] = 0.5*(data->y[topo[12+i]]+data->y[topo[12+(i+1)%4]]);
6098
data->z[topo[i+20]] = 0.5*(data->z[topo[12+i]]+data->z[topo[12+(i+1)%4]]);
6099
}
6100
data->x[topo[26]] = 0.5*(data->x[topo[0]]+data->x[topo[6]]);
6101
data->y[topo[26]] = 0.5*(data->y[topo[0]]+data->y[topo[6]]);
6102
data->z[topo[26]] = 0.5*(data->z[topo[0]]+data->z[topo[6]]);
6103
}
6104
}
6105
}
6106
6107
/* Perform cylindrical coordinate transformation */
6108
if(grid->rotate)
6109
CylindricalCoordinateTransformation(data,grid->rotateradius1,
6110
grid->rotateradius2,grid->rotatecartesian);
6111
6112
cummaxsidetype = 0;
6113
sidetype = 0;
6114
6115
/* Extrude the 2D boundary conditions. Initially BCs typically have parents with
6116
different material. If due to selective extrusion they become the same then
6117
the extruded BC does not have that component. */
6118
for(j=0;j<data->noboundaries;j++) {
6119
if(!bound[j].created) continue;
6120
6121
maxsidetype = 0;
6122
minsidetype = INT_MAX;
6123
side = 0;
6124
level = 0;
6125
6126
for(cellk=1;cellk <= grid->zcells ;cellk++) {
6127
for(k=1;k<=grid->zelems[cellk]; k++) {
6128
level++;
6129
6130
for(i=1;i<=boundxy[j].nosides;i++){
6131
6132
/* Find the parent element indexes and the corresponding material indexes */
6133
ind1 = (level-1)*dataxy->noelements + boundxy[j].parent[i];
6134
parent = indx[ind1];
6135
6136
if(parent) material = data->material[parent];
6137
else material = 0;
6138
6139
if(boundxy[j].parent2[i]) {
6140
ind2 = (level-1)*dataxy->noelements + boundxy[j].parent2[i];
6141
parent2 = indx[ind2];
6142
}
6143
else
6144
parent2 = 0;
6145
6146
if(parent2) material2 = data->material[parent2];
6147
else material2 = 0;
6148
6149
if((parent || parent2) && (material != material2)) {
6150
side++;
6151
6152
if(!parent & !parent2) printf("no parent = %d %d %d %d %d\n",parent,parent2,ind1,ind2,level);
6153
6154
sidetype = boundxy[j].types[i];
6155
bound[j].types[side] = sidetype;
6156
6157
maxsidetype = MAX( maxsidetype, sidetype );
6158
minsidetype = MIN( minsidetype, sidetype );
6159
6160
if(parent) {
6161
bound[j].parent[side] = parent;
6162
bound[j].parent2[side] = parent2;
6163
bound[j].side[side] = boundxy[j].side[i];
6164
bound[j].side2[side] = boundxy[j].side2[i];
6165
bound[j].material[side] = material;
6166
}
6167
else {
6168
bound[j].parent[side] = parent2;
6169
bound[j].parent2[side] = parent;
6170
bound[j].side[side] = boundxy[j].side2[i];
6171
bound[j].side2[side] = boundxy[j].side[i];
6172
bound[j].material[side] = material2;
6173
}
6174
6175
/* The sides have different convention for 1D initial elements */
6176
if(elemtype == 404) {
6177
if(bound[j].side[side] == 0) bound[j].side[side] = 3;
6178
if(bound[j].side2[side] == 0) bound[j].side2[side] = 3;
6179
}
6180
}
6181
}
6182
}
6183
}
6184
bound[j].nosides = side;
6185
cummaxsidetype = MAX( maxsidetype, cummaxsidetype );
6186
6187
if(info) {
6188
if(side)
6189
printf("Extruded BCs list %d of types [%d,%d] has %d elements.\n",
6190
j,minsidetype,maxsidetype,side);
6191
else
6192
printf("Extruded BCs list %d has no elements!\n",j);
6193
}
6194
6195
}
6196
6197
bcset = dataxy->noboundaries-1;
6198
6199
6200
if( usenames ) {
6201
for(i=1;i< MAXBODIES;i++) {
6202
if(dataxy->bodyname[i]) {
6203
if(!data->bodyname[i]) data->bodyname[i] = Cvector(0,MAXNAMESIZE);
6204
strcpy(data->bodyname[i],dataxy->bodyname[i]);
6205
}
6206
}
6207
for(i=1;i< MAXBCS;i++) {
6208
if(dataxy->boundaryname[i]) {
6209
if(!data->boundaryname[i]) data->boundaryname[i] = Cvector(0,MAXNAMESIZE);
6210
strcpy(data->boundaryname[i],dataxy->boundaryname[i]);
6211
}
6212
}
6213
data->bodynamesexist = TRUE;
6214
data->boundarynamesexist = TRUE;
6215
}
6216
6217
6218
/* Find the BCs that are created for constant z-levels.
6219
Here number all parent combinations so that each pair gets
6220
a new BC index. They are numbered by their order of appearance. */
6221
layerbcoffset = grid->layerbcoffset;
6222
6223
if(grid->layeredbc) {
6224
6225
if( !layerbcoffset ) sidetype = maxsidetype;
6226
6227
/* Find the BCs between layers. */
6228
if(grid->dimension == 3 || grid->rotatecartesian) {
6229
side = 0;
6230
level = 0;
6231
bclevel = 0;
6232
6233
6234
/* Go through extruded cells */
6235
for(cellk=1;cellk <= grid->zcells ;cellk++) {
6236
int swap,redo;
6237
redo = FALSE;
6238
6239
redolayer:
6240
maxsidetype = 0;
6241
minsidetype = INT_MAX;
6242
6243
/* Go through element layers within cells */
6244
for(k=1;k<=grid->zelems[cellk]; k++) {
6245
level++;
6246
if(!(k == 1) && !(cellk == grid->zcells && k==grid->zelems[cellk])) continue;
6247
6248
/* Last cell in case of last just one element layer gives rise to two BCs */
6249
if(cellk == grid->zcells && k == grid->zelems[cellk]) {
6250
if(grid->zelems[cellk] == 1)
6251
redo = TRUE;
6252
else {
6253
level++;
6254
}
6255
}
6256
6257
if(grid->rotatecartesian && cellk % 2 == 1) continue;
6258
if(grid->rotatecartesian && k != 1) continue;
6259
6260
/* If layred bc offset is defined then the BCs are numbered deterministically
6261
otherwise there is a complicated method of defining the BC index so that
6262
indexes would be used in order. */
6263
if(!layerbcoffset) {
6264
for(i=0;i<MAXNEWBC;i++) {
6265
refmaterial1[i] = 0;
6266
refmaterial2[i] = 0;
6267
refsidetype[i] = 0;
6268
}
6269
}
6270
side = 0;
6271
bcset++;
6272
bclevel++;
6273
maxsidetype = 0;
6274
minsidetype = INT_MAX;
6275
6276
for(i=1;i<=dataxy->noelements;i++){
6277
origtype = dataxy->elementtypes[i];
6278
nonodes2d = origtype % 100;
6279
6280
if(origtype == 202)
6281
elemtype = 404;
6282
else if(origtype == 303)
6283
elemtype = 706;
6284
else if(origtype == 404)
6285
elemtype = 808;
6286
else if(origtype == 408)
6287
elemtype = 820;
6288
else if(origtype == 409)
6289
elemtype = 827;
6290
6291
/* Check the parent elements of the layers. Only create a BC if the parents are
6292
different. */
6293
ind1 = (level-2)*dataxy->noelements + i;
6294
if(ind1 < 1)
6295
parent = 0;
6296
else
6297
parent = indx[ind1];
6298
6299
ind2 = (level-1)*dataxy->noelements + i;
6300
if(ind2 > indxlength)
6301
parent2 = 0;
6302
else
6303
parent2 = indx[ind2];
6304
6305
/* If only 2nd parent is given swap the order */
6306
if(parent == 0 && parent2 != 0) {
6307
parent = parent2;
6308
parent2 = 0;
6309
swap = 1;
6310
}
6311
else {
6312
swap = 0;
6313
}
6314
6315
if(!parent) continue;
6316
6317
/* Get the materials related to the parents */
6318
material = data->material[parent];
6319
if(parent2)
6320
material2 = data->material[parent2];
6321
else
6322
material2 = 0;
6323
6324
if(grid->rotatecartesian && !material2) {
6325
if(origtype == 303) GetElementSide(parent,4-swap,1,data,sideind,&sideelemtype);
6326
else GetElementSide(parent,5-swap,1,data,sideind,&sideelemtype);
6327
meanx = meany = 0.0;
6328
if(cellk%4 == 2) {
6329
for(l=0;l<sideelemtype%100;l++) {
6330
meanx += data->y[sideind[l]];
6331
meany += data->z[sideind[l]];
6332
}
6333
}
6334
else {
6335
for(l=0;l<sideelemtype%100;l++) {
6336
meanx += data->x[sideind[l]];
6337
meany += data->z[sideind[l]];
6338
}
6339
}
6340
meanx = fabs(meanx)/(sideelemtype%100);
6341
meany = fabs(meany)/(sideelemtype%100);
6342
6343
if(fabs(meanx - grid->rotateradius1) > 1.0e-12) {
6344
material2 = material;
6345
}
6346
else {
6347
for(m=0;m<grid->xcells && grid->x[m]+1.0e-12 < meanx;m++);
6348
for(n=0;n<grid->ycells && grid->y[n]+1.0e-12 < meany;n++);
6349
material2 = grid->structure[n][m+1];
6350
}
6351
}
6352
6353
/* Create bc index only if the materials are different */
6354
if(material != material2) {
6355
side++;
6356
6357
bound[bcset].nosides = side;
6358
bound[bcset].parent[side] = parent;
6359
bound[bcset].parent2[side] = parent2;
6360
bound[bcset].material[side] = material;
6361
6362
if(origtype == 303) {
6363
bound[bcset].side[side] = 4-swap;
6364
bound[bcset].side2[side] = 3+swap;
6365
}
6366
else {
6367
bound[bcset].side[side] = 5-swap;
6368
bound[bcset].side2[side] = 4+swap;
6369
}
6370
6371
/* Simple and deterministic, and complex and continuous numbering */
6372
if(layerbcoffset) {
6373
sidetype = bclevel * layerbcoffset + dataxy->material[i];
6374
bound[bcset].types[side] = sidetype;
6375
maxsidetype = MAX( sidetype, maxsidetype );
6376
minsidetype = MIN( sidetype, minsidetype );
6377
}
6378
else {
6379
for(m=0;m<MAXNEWBC;m++) {
6380
if(refmaterial1[m] == material && refmaterial2[m] == material2) {
6381
break;
6382
}
6383
else if(refmaterial1[m] == 0 && refmaterial2[m] == 0) {
6384
refmaterial1[m] = material;
6385
refmaterial2[m] = material2;
6386
sidetype++;
6387
maxsidetype = MAX( sidetype, maxsidetype );
6388
minsidetype = MIN( sidetype, minsidetype );
6389
refsidetype[m] = sidetype;
6390
break;
6391
}
6392
else if(m == MAXNEWBC-1) {
6393
printf("Layer includes more than %d new BCs!\n",MAXNEWBC);
6394
}
6395
}
6396
l = refsidetype[m];
6397
bound[bcset].types[side] = l;
6398
6399
6400
if( usenames ) {
6401
if(!data->boundaryname[l]) data->boundaryname[l] = Cvector(0,MAXNAMESIZE);
6402
if( bclevel == 1 )
6403
sprintf(data->boundaryname[l],"%s%s",
6404
dataxy->bodyname[dataxy->material[i]],"_Start");
6405
else if( cellk == grid->zcells )
6406
sprintf(data->boundaryname[l],"%s%s",
6407
dataxy->bodyname[dataxy->material[i]],"_End");
6408
else
6409
sprintf(data->boundaryname[l],"%s%s%d",
6410
dataxy->bodyname[dataxy->material[i]],"_Level",bclevel);
6411
}
6412
6413
6414
}
6415
6416
}
6417
}
6418
6419
if(info) {
6420
if(side)
6421
printf("Layer BCs list %d of types [%d,%d] has %d elements.\n",
6422
bcset,minsidetype,maxsidetype,side);
6423
else
6424
printf("Layer BCs list %d has no elements!\n",bcset);
6425
}
6426
6427
if(redo == TRUE) {
6428
goto redolayer;
6429
}
6430
}
6431
}
6432
}
6433
}
6434
6435
6436
/* Create four additional boundaries that may be used to force
6437
symmetry constraints. These are only created if the object
6438
is only partially rotated. */
6439
6440
bcset++;
6441
if(grid->rotate && grid->rotateblocks < 4) {
6442
int o,p;
6443
int blocks, maxradi,addtype;
6444
Real eps,fii,rad,meanrad,maxrad,xc,yc,dfii,fii0,rads[4],fiis[4];
6445
6446
o = p = 0;
6447
eps = 1.0e-3;
6448
blocks = grid->rotateblocks;
6449
6450
for(element=1;element<=data->noelements;element++) {
6451
6452
for(side=0;side<6;side++) {
6453
GetElementSide(element,side,1,data,&sideind[0],&sideelemtype);
6454
6455
meanrad = 0.0;
6456
maxrad = 0.0;
6457
maxradi = 0;
6458
6459
j = sideelemtype/100;
6460
if(j==1) break;
6461
6462
for(i=0;i<j;i++) {
6463
xc = data->x[sideind[i]];
6464
yc = data->y[sideind[i]];
6465
6466
rad = sqrt(yc*yc+xc*xc);
6467
fii = 2*atan2(yc,xc)/FM_PI; /* Map fii to [0 4] */
6468
6469
rads[i] = rad;
6470
fiis[i] = fii;
6471
6472
if(rad > maxrad) {
6473
maxrad = rad;
6474
maxradi = i;
6475
}
6476
meanrad += rad / j;
6477
}
6478
6479
fii0 = fiis[maxradi];
6480
dfii = 0.0;
6481
for(i=0;i<4;i++) {
6482
if(rads[i] > eps * maxrad) {
6483
if( fabs(fiis[i]-fii0) > dfii) dfii = fabs(fiis[i]-fii0);
6484
}
6485
}
6486
6487
if(dfii > eps) continue;
6488
6489
addtype = -1;
6490
6491
/* BCs for zero angle */
6492
if(fabs(fii0) < eps) {
6493
o++;
6494
if(meanrad < grid->rotateradius2)
6495
addtype = 0;
6496
else
6497
addtype = 2;
6498
}
6499
/* BCs for angles 90, 180 or 270. */
6500
else if(fabs(fii0-blocks) < eps) {
6501
p++;
6502
if(meanrad < grid->rotateradius2)
6503
addtype = 1;
6504
else
6505
addtype = 3;
6506
}
6507
6508
if( addtype >= 0) {
6509
bound[bcset+addtype].nosides++;
6510
k = bound[bcset+addtype].nosides;
6511
bound[bcset+addtype].side[k] = side;
6512
bound[bcset+addtype].parent[k] = element;
6513
bound[bcset+addtype].types[k] = sidetype+addtype+1;
6514
}
6515
}
6516
}
6517
6518
for(addtype=0;addtype<4;addtype++) {
6519
l = bcset+addtype;
6520
if(bound[l].nosides == 0) {
6521
bound[l].created = FALSE;
6522
}
6523
else {
6524
bound[l].created = TRUE;
6525
if(info) {
6526
if(bound[l].nosides)
6527
printf("Symmetry BCs list %d of type %d has %d elements.\n",
6528
l,sidetype+addtype+1,bound[l].nosides);
6529
else
6530
printf("Symmetry BCs list %d has no elements!\n",l);
6531
}
6532
}
6533
}
6534
bcset += 4;
6535
}
6536
data->noboundaries = bcset+1;
6537
6538
6539
/* Renumber the element nodes so that all integers are used.
6540
Allocate new space for the new nodes and their coordinates. */
6541
6542
for(i=1;i<=data->noknots;i++)
6543
indx[i] = 0;
6544
6545
for(element=1;element<=data->noelements;element++) {
6546
nonodes3d = data->elementtypes[element] % 100;
6547
for(i=0;i<nonodes3d;i++)
6548
indx[data->topology[element][i]] = 1;
6549
}
6550
6551
j = 0;
6552
for(i=1;i<=data->noknots;i++)
6553
if(indx[i])
6554
indx[i] = ++j;
6555
6556
if(j < data->noknots) {
6557
printf("%d original nodes moved to %d new ones.\n",data->noknots,j);
6558
newx = Rvector(1,j);
6559
for(i=1;i<=data->noknots;i++)
6560
newx[indx[i]] = data->x[i];
6561
6562
newy = data->x;
6563
data->x = newx;
6564
for(i=1;i<=data->noknots;i++)
6565
newy[indx[i]] = data->y[i];
6566
6567
newz = data->y;
6568
data->y = newy;
6569
for(i=1;i<=data->noknots;i++)
6570
newz[indx[i]] = data->z[i];
6571
6572
free_Rvector(data->z,1,data->noknots);
6573
data->z = newz;
6574
data->noknots = j;
6575
6576
for(element=1;element<=data->noelements;element++) {
6577
nonodes3d = data->elementtypes[element] % 100;
6578
for(i=0;i<nonodes3d;i++)
6579
data->topology[element][i] = indx[data->topology[element][i]];
6580
}
6581
}
6582
6583
if(grid->rotate) {
6584
ReorderElements(data,bound,FALSE,corder,info);
6585
6586
CylindricalCoordinateImprove(data,grid->rotateimprove,
6587
grid->rotateradius1,grid->rotateradius2);
6588
6589
if(0 && grid->rotatecurve)
6590
CylindricalCoordinateCurve(data,grid->curvezet,
6591
grid->curverad,grid->curveangle);
6592
6593
if(grid->rotatecartesian)
6594
SeparateMainaxisBoundaries(data,bound);
6595
6596
printf("Created %d elements and %d nodes by rotation of %d degrees.\n",
6597
data->noelements,data->noknots,90*grid->rotateblocks);
6598
}
6599
else if(grid->dimension == 3)
6600
if(info) printf("Created %d elements and %d nodes by extruding the 2D geometry\n",
6601
data->noelements,data->noknots);
6602
6603
free_Ivector(indx,0,indxlength);
6604
6605
6606
/* Enforce constant helicity for the mesh if requested */
6607
if( grid->zhelicityexists ) {
6608
Real helicity,fii,x,y,z,minz,maxz;
6609
6610
helicity = (FM_PI/180.0)*grid->zhelicity;
6611
6612
minz = maxz = data->z[1];
6613
for(i=1;i<=data->noknots;i++) {
6614
minz = MIN(minz,data->z[i]);
6615
maxz = MAX(maxz,data->z[i]);
6616
}
6617
for(i=1;i<=data->noknots;i++) {
6618
x = data->x[i];
6619
y = data->y[i];
6620
z = data->z[i];
6621
fii = helicity*(z-minz)/(maxz-minz);
6622
6623
data->x[i] = cos(fii)*x - sin(fii)*y;
6624
data->y[i] = sin(fii)*x + cos(fii)*y;
6625
}
6626
if(info) printf("Applied helicity of %12.5le degrees\n",grid->zhelicity);
6627
}
6628
6629
}
6630
6631
6632
6633
void ReduceElementOrder(struct FemType *data,int matmin,int matmax)
6634
/* Reduces the element order at material interval [matmin,matmax] */
6635
{
6636
int i,j,element,material,elemcode1,elemcode2,maxnode,reduced;
6637
int *indx=NULL;
6638
Real *newx=NULL,*newy=NULL,*newz=NULL;
6639
6640
indx = Ivector(0,data->noknots);
6641
for(i=0;i<=data->noknots;i++)
6642
indx[i] = 0;
6643
reduced = 0;
6644
6645
for(element=1;element<=data->noelements;element++) {
6646
elemcode1 = data->elementtypes[element];
6647
material = data->material[element];
6648
elemcode2 = elemcode1;
6649
if(material >= matmin && material <= matmax)
6650
elemcode2 = 101*(elemcode1/100);
6651
if(elemcode2 == 505) elemcode2 = 504; /* tetrahedron */
6652
else if(elemcode2 == 606) elemcode2 = 605; /* pyramid */
6653
else if(elemcode2 == 707) elemcode2 = 706; /* prism */
6654
#if 0
6655
printf("element=%d codes=[%d,%d]\n",element,elemcode1,elemcode2);
6656
printf("mat=%d interval=[%d,%d]\n",material,matmin,matmax);
6657
#endif
6658
if(elemcode2 < elemcode1)
6659
reduced++;
6660
maxnode = elemcode2%100;
6661
for(i=0;i<maxnode;i++)
6662
indx[data->topology[element][i]] = 1;
6663
data->elementtypes[element] = elemcode2;
6664
}
6665
6666
printf("The element order is reduced in %d elements at interval [%d,%d]\n",
6667
reduced,matmin,matmax);
6668
6669
j = 0;
6670
for(i=1;i<=data->noknots;i++)
6671
if(indx[i])
6672
indx[i] = ++j;
6673
6674
printf("%d original nodes moved to %d new ones.\n",data->noknots,j);
6675
6676
newx = Rvector(1,j);
6677
newy = Rvector(1,j);
6678
newz = Rvector(1,j);
6679
6680
for(i=1;i<=data->noknots;i++) {
6681
newx[indx[i]] = data->x[i];
6682
newy[indx[i]] = data->y[i];
6683
newz[indx[i]] = data->z[i];
6684
}
6685
6686
free_Rvector(data->x,1,data->noknots);
6687
free_Rvector(data->y,1,data->noknots);
6688
free_Rvector(data->z,1,data->noknots);
6689
6690
data->x = newx;
6691
data->y = newy;
6692
data->z = newz;
6693
data->noknots = j;
6694
6695
for(element=1;element<=data->noelements;element++) {
6696
maxnode = data->elementtypes[element]%100;
6697
for(i=0;i<maxnode;i++)
6698
data->topology[element][i] = indx[data->topology[element][i]];
6699
}
6700
}
6701
6702
6703
6704
6705
void MergeElements(struct FemType *data,struct BoundaryType *bound,
6706
int manual,Real corder[],Real eps,int mergebounds,int info)
6707
{
6708
int i,j,k,l;
6709
int noelements,noknots,newnoknots,nonodes;
6710
int *mergeindx=NULL,*doubles=NULL;
6711
Real *newx=NULL,*newy=NULL,*newz=NULL;
6712
Real cx,cy,cz,dx,dy,dz,cdist,dist;
6713
6714
ReorderElements(data,bound,manual,corder,TRUE);
6715
6716
/* The known ordering by vector corder[] is used to
6717
reduce the cost of finding the merged nodes. */
6718
6719
cx = corder[0];
6720
cy = corder[1];
6721
cz = corder[2];
6722
6723
/* Normalizing for future use */
6724
cdist = sqrt(cx*cx+cy*cy+cz*cz);
6725
cx /= cdist;
6726
cy /= cdist;
6727
cz /= cdist;
6728
6729
noelements = data->noelements;
6730
noknots = data->noknots;
6731
newnoknots = noknots;
6732
6733
mergeindx = Ivector(1,noknots);
6734
for(i=1;i<=noknots;i++)
6735
mergeindx[i] = 0;
6736
6737
doubles = Ivector(1,noknots);
6738
for(i=1;i<=noknots;i++)
6739
doubles[i] = 0;
6740
6741
if(info) printf("Merging nodes close (%.3lg) to one another.\n",eps);
6742
6743
dz = 0.0;
6744
for(i=1;i<noknots;i++) {
6745
if(mergeindx[i]) continue;
6746
6747
for(j=i+1; j<=noknots;j++) {
6748
if(mergeindx[j]) continue;
6749
6750
dx = data->x[i] - data->x[j];
6751
dy = data->y[i] - data->y[j];
6752
dz = data->z[i] - data->z[j];
6753
6754
if(fabs(cx*dx+cy*dy+cz*dz) > eps) break;
6755
6756
dist = dx*dx + dy*dy + dz*dz;
6757
6758
if(dist < eps*eps) {
6759
doubles[i] = doubles[j] = TRUE;
6760
mergeindx[j] = -i;
6761
newnoknots--;
6762
}
6763
}
6764
}
6765
6766
if(mergebounds) MergeBoundaries(data,bound,doubles,info);
6767
6768
6769
j = 0;
6770
for(i=1;i<=noknots;i++)
6771
if(mergeindx[i] == 0)
6772
mergeindx[i] = ++j;
6773
6774
for(i=1;i<=noknots;i++) {
6775
if(mergeindx[i] < 0)
6776
mergeindx[i] = mergeindx[-mergeindx[i]];
6777
}
6778
6779
printf("%d original nodes merged to %d new nodes.\n",
6780
noknots,newnoknots);
6781
6782
newx = Rvector(1,newnoknots);
6783
newy = Rvector(1,newnoknots);
6784
newz = Rvector(1,newnoknots);
6785
6786
for(i=1;i<=noknots;i++) {
6787
newx[mergeindx[i]] = data->x[i];
6788
newy[mergeindx[i]] = data->y[i];
6789
newz[mergeindx[i]] = data->z[i];
6790
}
6791
6792
free_Rvector(data->x,1,data->noknots);
6793
free_Rvector(data->y,1,data->noknots);
6794
free_Rvector(data->z,1,data->noknots);
6795
6796
data->x = newx;
6797
data->y = newy;
6798
data->z = newz;
6799
6800
#if 0
6801
if(info) printf("Merging the topologies.\n");
6802
#endif
6803
6804
l = 0;
6805
for(j=1;j<=noelements;j++) {
6806
nonodes = data->elementtypes[j] % 100;
6807
for(i=0;i<nonodes;i++) {
6808
k = data->topology[j][i];
6809
data->topology[j][i] = mergeindx[k];
6810
}
6811
}
6812
6813
data->noknots = newnoknots;
6814
free_Ivector(mergeindx,1,noknots);
6815
6816
if(info) printf("Merging of nodes is complete.\n");
6817
}
6818
6819
6820
6821
void MergeBoundaries(struct FemType *data,struct BoundaryType *bound,int *doubles,int info)
6822
{
6823
int i,i2,j,k,l,totsides,newsides,sidenodes,sideelemtype,side;
6824
int parent,sideind[MAXNODESD1];
6825
6826
totsides = 0;
6827
newsides = 0;
6828
6829
if(info) printf("Eliminating boundaries at joined nodes\n");
6830
6831
for(j=0;j<MAXBOUNDARIES;j++) {
6832
if(!bound[j].created) continue;
6833
if(!bound[j].nosides) continue;
6834
6835
i2 = 0;
6836
for(i=1;i<=bound[j].nosides;i++) {
6837
6838
parent = bound[j].parent[i];
6839
side = bound[j].side[i];
6840
6841
GetElementSide(parent,side,1,data,sideind,&sideelemtype);
6842
sidenodes = sideelemtype % 100;
6843
6844
l = 0;
6845
for(k=0;k<sidenodes;k++)
6846
if(doubles[sideind[k]]) l++;
6847
6848
if(l < sidenodes) {
6849
i2++;
6850
6851
if(i != i2) {
6852
bound[j].parent[i2] = bound[j].parent[i];
6853
bound[j].parent2[i2] = bound[j].parent2[i];
6854
bound[j].side[i2] = bound[j].side[i];
6855
bound[j].side2[i2] = bound[j].side2[i];
6856
bound[j].types[i2] = bound[j].types[i];
6857
bound[j].normal[i2] = bound[j].normal[i];
6858
}
6859
}
6860
6861
}
6862
totsides += bound[j].nosides;
6863
newsides += i2;
6864
bound[j].nosides = i2;
6865
if(!i2) bound[j].created = FALSE;
6866
}
6867
6868
if(info) printf("Eliminated %d boundaries from original set of %d.\n",totsides-newsides,totsides);
6869
6870
}
6871
6872
6873
6874
void IsoparametricElements(struct FemType *data,struct BoundaryType *bound,
6875
int bcstoo,int info)
6876
{
6877
int i,j,k;
6878
int noelements,noknots;
6879
int element,side,sideelemtype,sidenodes,elemtype;
6880
int *bcindx=NULL,*topo=NULL,sideind[MAXNODESD1];
6881
Real *x=NULL,*y=NULL,*z=NULL;
6882
6883
noelements = data->noelements;
6884
noknots = data->noknots;
6885
x = data->x;
6886
y = data->y;
6887
z = data->z;
6888
6889
bcindx = Ivector(1,noknots);
6890
for(i=1;i<=noknots;i++)
6891
bcindx[i] = FALSE;
6892
6893
for(j=0;j < MAXBOUNDARIES;j++) {
6894
if(!bound[j].created) continue;
6895
6896
for(i=1; i <= bound[j].nosides; i++) {
6897
element = bound[j].parent[i];
6898
side = bound[j].side[i];
6899
6900
GetElementSide(element,side,1,data,sideind,&sideelemtype);
6901
6902
sidenodes = sideelemtype%100;
6903
6904
for(k=0;k<sidenodes;k++)
6905
bcindx[sideind[k]] = TRUE;
6906
}
6907
}
6908
6909
for(j=1;j<=noelements;j++) {
6910
elemtype = data->elementtypes[j];
6911
topo = data->topology[j];
6912
6913
if(elemtype == 306) {
6914
for(i=0;i<3;i++) {
6915
if(!bcindx[topo[i+3]]) {
6916
x[topo[i+3]] = 0.5*(x[topo[i]]+x[topo[(i+1)%3]]);
6917
y[topo[i+3]] = 0.5*(y[topo[i]]+y[topo[(i+1)%3]]);
6918
}
6919
}
6920
6921
}
6922
else if(elemtype == 310) {
6923
for(i=0;i<3;i++) {
6924
if(!bcindx[topo[2*i+3]]) {
6925
x[topo[2*i+3]] = (2.0*x[topo[i]]+1.0*x[topo[(i+1)%3]])/3.0;
6926
x[topo[2*i+4]] = (1.0*x[topo[i]]+2.0*x[topo[(i+1)%3]])/3.0;
6927
y[topo[2*i+3]] = (2.0*y[topo[i]]+1.0*y[topo[(i+1)%3]])/3.0;
6928
y[topo[2*i+4]] = (1.0*y[topo[i]]+2.0*y[topo[(i+1)%3]])/3.0;
6929
}
6930
}
6931
x[topo[9]] = (x[topo[0]]+x[topo[1]]+x[topo[2]])/3.0;
6932
y[topo[9]] = (y[topo[0]]+y[topo[1]]+y[topo[2]])/3.0;
6933
}
6934
else if(elemtype == 408 || elemtype == 409) {
6935
for(i=0;i<4;i++) {
6936
if(!bcindx[topo[i+4]]) {
6937
x[topo[i+4]] = 0.5*(x[topo[i]]+x[topo[(i+1)%4]]);
6938
y[topo[i+4]] = 0.5*(y[topo[i]]+y[topo[(i+1)%4]]);
6939
}
6940
}
6941
if(elemtype == 409) {
6942
x[topo[8]] = 0.25*(x[topo[0]]+x[topo[1]]+x[topo[2]]+x[topo[3]]);
6943
y[topo[8]] = 0.25*(y[topo[0]]+y[topo[1]]+y[topo[2]]+y[topo[3]]);
6944
}
6945
}
6946
else if(elemtype == 412 || elemtype == 416) {
6947
for(i=0;i<4;i++) {
6948
if(!bcindx[topo[2*i+4]]) {
6949
x[topo[2*i+4]] = (2.0*x[topo[i]]+1.0*x[topo[(i+1)%4]])/3.0;
6950
x[topo[2*i+5]] = (1.0*x[topo[i]]+2.0*x[topo[(i+1)%4]])/3.0;
6951
y[topo[2*i+4]] = (2.0*y[topo[i]]+1.0*y[topo[(i+1)%4]])/3.0;
6952
y[topo[2*i+5]] = (1.0*y[topo[i]]+2.0*y[topo[(i+1)%4]])/3.0;
6953
}
6954
}
6955
if(elemtype == 416) {
6956
Real xmean,ymean;
6957
xmean = (x[topo[0]]+x[topo[1]]+x[topo[2]]+x[topo[3]])/4.0;
6958
ymean = (y[topo[0]]+y[topo[1]]+y[topo[2]]+y[topo[3]])/4.0;
6959
for(i=0;i<4;i++) {
6960
x[topo[11+i]] = (2.*xmean + 1.0*x[i]) / 3.0;
6961
y[topo[11+i]] = (2.*ymean + 1.0*y[i]) / 3.0;
6962
}
6963
}
6964
}
6965
else {
6966
printf("IsoparametricElements: Not implemented for elementtype %d\n",elemtype);
6967
}
6968
}
6969
6970
if(info) printf("The elements were forced to be isoparametric\n");
6971
}
6972
6973
6974
6975
void ElementsToBoundaryConditions(struct FemType *data,
6976
struct BoundaryType *bound,int retainorphans,int info)
6977
{
6978
int i,j,k,l,sideelemtype,sideelemtype2,elemind,elemind2,sideelem,sameelem;
6979
int sideind[MAXNODESD1],sideind2[MAXNODESD1],elemsides,side,hit,same,minelemtype;
6980
int sidenodes,sidenodes2,maxelemtype,elemtype,elemdim,sideelements,material;
6981
int *moveelement=NULL,*parentorder=NULL,*possible=NULL,**invtopo=NULL;
6982
int noelements,maxpossible,noknots,maxelemsides,twiceelem,sideelemdim,minelemdim,maxelemdim;
6983
int debug,unmoved,removed,elemhits,loopdim,lowdimbulk;
6984
int notfound,*notfounds=NULL,movenames;
6985
6986
6987
if(info) {
6988
printf("Moving bulk elements to boundary elements\n");
6989
if(0) printf("Trying to retain orphans: %d\n",retainorphans);
6990
}
6991
6992
for(j=0;j < MAXBOUNDARIES;j++)
6993
bound[j].created = FALSE;
6994
for(j=0;j < MAXBOUNDARIES;j++)
6995
bound[j].nosides = 0;
6996
6997
noelements = data->noelements;
6998
noknots = data->noknots;
6999
7000
movenames = (data->bodynamesexist && !data->boundarynamesexist);
7001
if(data->bodynamesexist && info) {
7002
if(movenames)
7003
printf("Moving boundarynames together with elements\n");
7004
else
7005
printf("Assuming that boundaries names are already Ok!\n");
7006
}
7007
7008
maxelemtype = GetMaxElementType(data);
7009
if(info) printf("Leading bulk elementtype is %d\n",maxelemtype);
7010
7011
minelemtype = GetMinElementType(data);
7012
if(info) printf("Trailing bulk elementtype is %d\n",minelemtype);
7013
7014
maxelemdim = GetElementDimension(maxelemtype);
7015
minelemdim = GetElementDimension(minelemtype);
7016
if( maxelemdim - minelemdim == 0) {
7017
if(info) printf("No lower dimensional elements present!\n");
7018
return;
7019
}
7020
7021
if(maxelemdim-minelemdim > 1 ) {
7022
int **tagcount;
7023
int mintag,maxtag,tag,overlap;
7024
7025
mintag=maxtag=tag=overlap=-1;
7026
7027
if(info) printf("Checking that different dimensions have unique boundary tags!\n");
7028
7029
for(k=0;k<=2;k++) {
7030
for(i=1;i<=noelements;i++) {
7031
elemdim = GetElementDimension(data->elementtypes[i]);
7032
tag = data->material[i];
7033
7034
/* Get the tag interval for all elements */
7035
if(k==0) {
7036
if(maxtag==-1) {
7037
mintag = maxtag = tag;
7038
}
7039
else {
7040
mintag = MIN(mintag,tag);
7041
maxtag = MAX(maxtag,tag);
7042
}
7043
}
7044
7045
/* Count the number of tags for each dimensional */
7046
else if(k==1) {
7047
tagcount[elemdim][tag] += 1;
7048
}
7049
7050
/* Set the new tags for lower dimensions */
7051
else if(k==2) {
7052
if(elemdim < maxelemdim ) {
7053
data->material[i] = tagcount[elemdim][tag];
7054
}
7055
}
7056
}
7057
7058
if(k==0) {
7059
if(info) printf("Tag interval for boundaries: [%d %d]\n",mintag,maxtag);
7060
tagcount = Imatrix(0,maxelemdim,mintag,maxtag);
7061
for(i=0;i<=maxelemdim;i++)
7062
for(j=mintag;j<=maxtag;j++)
7063
tagcount[i][j] = 0;
7064
}
7065
else if(k==1) {
7066
for(j=mintag;j<=maxtag;j++) {
7067
overlap = 0;
7068
for(i=0;i<maxelemdim;i++)
7069
if(tagcount[i][j]) overlap++;
7070
if(overlap>1) break;
7071
}
7072
if(overlap>1) {
7073
if(info) printf("We have an overlap, applying offsets!\n");
7074
tag = 0;
7075
for(i=maxelemdim-1;i>=0;i--)
7076
for(j=mintag;j<=maxtag;j++) {
7077
if(tagcount[i][j]) {
7078
if(tag+1 <= j) {
7079
tag = j;
7080
}
7081
else {
7082
tag++;
7083
if(info) printf("Replacing tag in %d-dim %d -> %d\n",i,j,tag);
7084
}
7085
tagcount[i][j] = tag;
7086
}
7087
}
7088
}
7089
else {
7090
if(info) printf("No overlap, no offsets needed!\n");
7091
break;
7092
}
7093
}
7094
else if(k==2) {
7095
if(info) printf("Renumbered tags for boundary elements!\n");
7096
}
7097
}
7098
free_Imatrix(tagcount,0,maxelemdim,mintag,maxtag);
7099
}
7100
7101
moveelement = Ivector(1,noelements);
7102
7103
sideelements = 0;
7104
maxelemtype = 0;
7105
maxelemsides = 0;
7106
unmoved = 0;
7107
removed = 0;
7108
notfound = 0;
7109
lowdimbulk = 0;
7110
7111
for(i=1;i<=noelements;i++) {
7112
moveelement[i] = FALSE;
7113
sideelemdim = GetElementDimension(data->elementtypes[i]);
7114
7115
/* Lower dimensional elements are candidates to become BC elements */
7116
moveelement[i] = maxelemdim - sideelemdim;
7117
if(moveelement[i]) sideelements++;
7118
}
7119
if(info) printf("There are %d (out of %d) lower dimensional elements.\n",
7120
sideelements,noelements);
7121
if(sideelements == 0) return;
7122
7123
AllocateBoundary(bound,sideelements);
7124
7125
/* Compute maximum number of hits for inverse topology */
7126
possible = Ivector(1,noknots);
7127
for(i=1;i<=noknots;i++) possible[i] = 0;
7128
for(elemind=1;elemind <= data->noelements;elemind++) {
7129
/* if(moveelement[elemind]) continue; */
7130
elemtype = data->elementtypes[elemind];
7131
if(elemtype < 200 ) continue;
7132
for(i=0;i<data->elementtypes[elemind]%100;i++) {
7133
j = data->topology[elemind][i];
7134
possible[j] += 1;
7135
}
7136
}
7137
7138
j = 1;
7139
maxpossible = possible[1];
7140
for(i=1;i<=noknots;i++) {
7141
if(maxpossible < possible[i]) {
7142
maxpossible = possible[i];
7143
j = i;
7144
}
7145
}
7146
if(info) printf("Node %d belongs to maximum of %d elements\n",j,maxpossible);
7147
7148
/* Make a table showing to which elements a node belongs to
7149
Include only the potential parents which are not to be moved to BCs. */
7150
invtopo = Imatrix(1,noknots,1,maxpossible);
7151
for(i=1;i<=noknots;i++)
7152
for(j=1;j<=maxpossible;j++)
7153
invtopo[i][j] = 0;
7154
7155
for(elemind=1;elemind <= data->noelements;elemind++) {
7156
/* if(moveelement[elemind]) continue; */
7157
elemtype = data->elementtypes[elemind];
7158
if(elemtype < 200 ) continue;
7159
for(i=0;i<elemtype%100;i++) {
7160
k = data->topology[elemind][i];
7161
for(l=1;invtopo[k][l];l++);
7162
invtopo[k][l] = elemind;
7163
}
7164
}
7165
7166
sideelem = 0;
7167
sameelem = 0;
7168
twiceelem = 0;
7169
7170
debug = FALSE;
7171
7172
/* Go through boundary element candidates starting from higher dimension */
7173
for(loopdim=maxelemdim-1;loopdim>=0;loopdim--) {
7174
7175
if(debug) printf("loopdim = %d\n",loopdim);
7176
7177
for(elemind=1;elemind <= data->noelements;elemind++) {
7178
7179
if(!moveelement[elemind]) continue;
7180
7181
same = FALSE;
7182
sideelemtype = data->elementtypes[elemind];
7183
7184
/* Only check the elements that have right dimension */
7185
sideelemdim = GetElementDimension(sideelemtype);
7186
if(sideelemdim != loopdim ) continue;
7187
7188
sidenodes = sideelemtype % 100;
7189
for(i=0;i<sidenodes;i++)
7190
sideind[i] = data->topology[elemind][i];
7191
elemhits = 0;
7192
7193
if(debug) printf("Finding elem: %d %d %d\n",elemind,sideelemtype,sideelemdim);
7194
7195
7196
for(l=1;l<=maxpossible;l++) {
7197
elemind2 = invtopo[sideind[0]][l];
7198
7199
if(!elemind2) continue;
7200
7201
/* The parent should be an element that will not become BC element */
7202
if(moveelement[elemind2]) continue;
7203
7204
elemtype = data->elementtypes[elemind2];
7205
elemdim = GetElementDimension(elemtype);
7206
7207
/* Owner element should have higher dimension */
7208
if(elemdim <= sideelemdim ) continue;
7209
7210
hit = 0;
7211
for(i=0;i<sidenodes;i++)
7212
for(j=0;j<elemtype%100;j++)
7213
if(sideind[i] == data->topology[elemind2][j]) hit++;
7214
7215
if(hit < sidenodes) continue;
7216
7217
if(hit > sidenodes) printf("Strange: elemhits %d vs. elemnodes %d\n",hit,sidenodes);
7218
if(hit >= sidenodes) elemhits++;
7219
7220
for(side=0;side<=100;side++) {
7221
GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2);
7222
7223
if(sideelemtype2 == 0 ) break;
7224
7225
if(sideelemtype2 < 300 && sideelemtype > 300) break;
7226
if(sideelemtype2 < 200 && sideelemtype > 200) break;
7227
if(sideelemtype2 != sideelemtype ) continue;
7228
7229
sidenodes2 = sideelemtype2 % 100;
7230
if(sidenodes != sidenodes2) continue;
7231
if(sidenodes2 == 1 && sidenodes > 1) break;
7232
7233
hit = 0;
7234
for(i=0;i<sidenodes;i++)
7235
for(j=0;j<sidenodes2;j++)
7236
if(sideind[i] == sideind2[j]) hit++;
7237
7238
if(0) printf("%d hits in element %d\n",hit,sideelemtype2);
7239
if(hit == sidenodes) break;
7240
7241
if(sideelemtype != sideelemtype2) {
7242
printf("Hits in element after mismatch: %d vs. %d\n",sideelemtype,sideelemtype2);
7243
continue;
7244
}
7245
}
7246
if( sidenodes == 1 && !hit) {
7247
printf("elemind = %d sideind %d vs. ",elemind,sideind[0]);
7248
for(j=0;j<sidenodes2;j++)
7249
printf("%d ",sideind2[j]);
7250
printf("\n");
7251
}
7252
7253
if(hit < sidenodes || !sideelemtype2) {
7254
if(0) printf("Preliminary hit but not really: %d %d\n",hit,sidenodes);
7255
continue;
7256
}
7257
7258
if(same) {
7259
sameelem += 1;
7260
bound->parent2[sideelem] = elemind2;
7261
bound->side2[sideelem] = side;
7262
7263
if(debug) printf(" Found 2nd: %d %d %d\n",elemind,elemind2,side);
7264
goto foundtwo;
7265
}
7266
else {
7267
sideelem += 1;
7268
same = TRUE;
7269
if(debug) printf(" Found 1st: %d %d %d %d %d\n",elemind,elemind2,side,sideelemtype,sideelemtype2);
7270
7271
bound->parent[sideelem] = elemind2;
7272
bound->side[sideelem] = side;
7273
bound->parent2[sideelem] = 0;
7274
bound->side2[sideelem] = 0;
7275
material = data->material[elemind];
7276
bound->types[sideelem] = material;
7277
7278
if(sidenodes == 2) {
7279
if((sideind[0]-sideind[1])*(sideind2[0]-sideind2[1])<0)
7280
bound->normal[sideelem] = -1;
7281
}
7282
if(movenames) {
7283
data->boundarynamesexist = TRUE;
7284
if(material < MAXBODIES && material < MAXBCS) {
7285
if(!data->boundaryname[material]) {
7286
data->boundaryname[material] = Cvector(0,MAXNAMESIZE);
7287
if(data->bodyname[material]) {
7288
strcpy(data->boundaryname[material],data->bodyname[material]);
7289
free_Cvector(data->bodyname[material],0,MAXNAMESIZE);
7290
data->bodyname[material] = NULL;
7291
}
7292
else
7293
sprintf(data->boundaryname[material],"body%d",material);
7294
}
7295
}
7296
if(!strncmp(data->boundaryname[material],"body",4)) {
7297
strncpy(data->boundaryname[material],"bnry",4);
7298
}
7299
}
7300
7301
/* Only try to find two parents if the boundary element is one degree smaller than maximum dimension */
7302
if(moveelement[elemind] > 1) goto foundtwo;
7303
}
7304
}
7305
7306
if(!same) {
7307
/* If the element is of dimension DIM-1 then create a table showing where they are */
7308
if(retainorphans ) {
7309
/* If we have only one degree smaller unfound element then keep them as bulk elements. */
7310
if( moveelement[elemind] == 1) {
7311
moveelement[elemind] = 0;
7312
lowdimbulk++;
7313
if(debug) printf(" Bulk: %d\n",elemind);
7314
}
7315
else {
7316
if(!notfound) {
7317
notfounds = Ivector(1,noelements);
7318
for(i=1;i<=noelements;i++)
7319
notfounds[i] = FALSE;
7320
}
7321
notfound++;
7322
notfounds[elemind] = TRUE;
7323
7324
if(0) {
7325
printf("element: elemind = %d type = %d nodes = %d elemhits = %d\n",
7326
elemind,sideelemtype,sidenodes,elemhits);
7327
printf(" inds =");
7328
for(i=0;i<sidenodes;i++)
7329
printf(" %d ",sideind[i]);
7330
printf("\n");
7331
}
7332
7333
if(debug) printf(" Unfound: %d\n",elemind);
7334
}
7335
}
7336
else {
7337
if(debug) printf(" Removed: %d\n",elemind);
7338
7339
moveelement[elemind] = -1;
7340
removed += 1;
7341
}
7342
}
7343
7344
foundtwo:
7345
continue;
7346
7347
}
7348
7349
if(0) printf("Intermediate results: %d %d %d %d\n",twiceelem,sameelem,sideelem,removed);
7350
}
7351
7352
if(twiceelem) printf("Found %d sides that were multiply given\n",twiceelem);
7353
if(sameelem) printf("Found %d side elements that have two parents.\n",sameelem);
7354
7355
7356
if(sideelem == sideelements) {
7357
printf("Found correctly %d side elements.\n",sideelem);
7358
}
7359
else {
7360
printf("Studied %d lower dimensional elements\n",sideelements);
7361
printf("Defined %d side elements\n",sideelem);
7362
printf("Defined %d lower dimensional bulk elements\n",lowdimbulk);
7363
7364
bound->nosides = sideelem;
7365
7366
printf("Removing %d lower dimensional elements from the element list\n",removed);
7367
if(notfound) {
7368
if(0) printf("************************** WARNING **********************\n");
7369
if(retainorphans) {
7370
printf("Adding %d elements to boundary without parent information\n",notfound);
7371
7372
bound->elementtypes = Ivector(sideelem+1,sideelements);
7373
for(i=sideelem+1;i<=sideelements;i++) bound->elementtypes[i] = 0;
7374
7375
bound->topology = Imatrix(sideelem+1,sideelements,0,MAXNODESD2-1);
7376
7377
for(elemind=1;elemind <= data->noelements;elemind++) {
7378
if(!notfounds[elemind]) continue;
7379
sideelem++;
7380
7381
j = data->elementtypes[elemind];
7382
bound->elementtypes[sideelem] = j;
7383
7384
for(i=0;i<j%100;i++)
7385
bound->topology[sideelem][i] = data->topology[elemind][i];
7386
7387
/* Adding some constant here could be used for debugging */
7388
bound->types[sideelem] = data->material[elemind] + 1*10;
7389
bound->parent[sideelem] = 0;
7390
}
7391
bound->nosides = sideelem;
7392
}
7393
else {
7394
printf("Removing %d lower dimensional elements without parent information\n",notfound);
7395
}
7396
}
7397
}
7398
7399
/* Reorder remaining bulk elements */
7400
parentorder = Ivector(1,noelements);
7401
for(i=1;i<=noelements;i++)
7402
parentorder[i] = 0;
7403
7404
j = 0;
7405
for(i=1;i<=noelements;i++) {
7406
if(moveelement[i] == 0) {
7407
k = data->elementtypes[i];
7408
7409
j++;
7410
parentorder[i] = j;
7411
7412
if(debug) printf("Bulk is: %d %d\n",i,j);
7413
7414
if( i != j ) {
7415
data->material[j] = data->material[i];
7416
data->elementtypes[j] = data->elementtypes[i];
7417
for(l=0;l<k%100;l++)
7418
data->topology[j][l] = data->topology[i][l];
7419
}
7420
}
7421
}
7422
data->noelements = j;
7423
if(info) printf("Parent elements were reordered up to index %d.\n",j);
7424
7425
7426
/* Reorder boundary to point at the new arrangement of master elements */
7427
for(i=1;i<=bound->nosides;i++) {
7428
if(!bound->parent[i]) continue;
7429
7430
if( !parentorder[bound->parent[i]] ) {
7431
printf("Zero reorder: %d %d %d\n",i,bound->parent[i],bound->side[i]);
7432
bigerror("Sorry folks!");
7433
}
7434
7435
if(bound->parent[i]) bound->parent[i] = parentorder[bound->parent[i]];
7436
if(bound->parent2[i]) bound->parent2[i] = parentorder[bound->parent2[i]];
7437
7438
GetElementSide(bound->parent[i],bound->side[i],1,data,&sideind2[0],&sideelemtype2);
7439
7440
if(0) GetBoundaryElement(i,&bound[j],data,&sideind2[0],&sideelemtype2);
7441
}
7442
7443
if(info) printf("Moved %d elements (out of %d) to new positions\n",j,noelements);
7444
7445
free_Ivector(parentorder,1,noelements);
7446
7447
free_Ivector(moveelement,1,noelements);
7448
free_Ivector(possible,1,noknots);
7449
free_Imatrix(invtopo,1,noknots,1,maxpossible);
7450
if(notfound) free_Ivector(notfounds,1,noelements);
7451
7452
if(debug) printf("All done\n");
7453
7454
return;
7455
}
7456
7457
7458
int SideAndBulkMappings(struct FemType *data,struct BoundaryType *bound,struct ElmergridType *eg,int info)
7459
{
7460
int i,j,l,currenttype;
7461
7462
7463
if(eg->sidemappings) {
7464
if(info) printf("Renumbering boundary types with %d mappings\n",eg->sidemappings);
7465
7466
for(l=0;l<eg->sidemappings;l++)
7467
if(info) printf("Setting boundary types between %d and %d to %d\n",
7468
eg->sidemap[3*l],eg->sidemap[3*l+1],eg->sidemap[3*l+2]);
7469
7470
for(j=0;j < MAXBOUNDARIES;j++) {
7471
if(!bound[j].created) continue;
7472
7473
for(i=1; i <= bound[j].nosides; i++) {
7474
if((currenttype = bound[j].types[i])) {
7475
for(l=0;l<eg->sidemappings;l++) {
7476
if(currenttype >= eg->sidemap[3*l] && currenttype <= eg->sidemap[3*l+1]) {
7477
bound[j].types[i] = eg->sidemap[3*l+2];
7478
currenttype = -1;
7479
}
7480
}
7481
}
7482
}
7483
}
7484
if(info) printf("Renumbering boundary types finished\n");
7485
}
7486
7487
if(eg->bulkmappings) {
7488
if(info) printf("Renumbering bulk types with %d mappings\n",eg->bulkmappings);
7489
7490
for(l=0;l<eg->bulkmappings;l++)
7491
if(info) printf("Setting material types between %d and %d to %d\n",
7492
eg->bulkmap[3*l],eg->bulkmap[3*l+1],eg->bulkmap[3*l+2]);
7493
for(j=1;j<=data->noelements;j++) {
7494
currenttype = data->material[j];
7495
for(l=0;l<eg->bulkmappings;l++) {
7496
if(currenttype >= eg->bulkmap[3*l] && currenttype <= eg->bulkmap[3*l+1]) {
7497
data->material[j] = eg->bulkmap[3*l+2];
7498
currenttype = -1;
7499
}
7500
}
7501
}
7502
if(info) printf("Renumbering material indexes finished\n");
7503
}
7504
return(0);
7505
}
7506
7507
7508
7509
int SideAndBulkBoundaries(struct FemType *data,struct BoundaryType *bound,struct ElmergridType *eg,int info)
7510
{
7511
int l;
7512
int *boundnodes,noboundnodes;
7513
boundnodes = Ivector(1,data->noknots);
7514
7515
if(eg->bulkbounds) {
7516
for(l=0;l<eg->bulkbounds;l++) {
7517
FindBulkBoundary(data,eg->bulkbound[3*l],eg->bulkbound[3*l+1],
7518
boundnodes,&noboundnodes,info);
7519
FindNewBoundaries(data,bound,boundnodes,eg->bulkbound[3*l+2],1,info);
7520
}
7521
}
7522
if(eg->boundbounds) {
7523
for(l=0;l<eg->boundbounds;l++) {
7524
FindBoundaryBoundary(data,bound,eg->boundbound[3*l],eg->boundbound[3*l+1],
7525
boundnodes,&noboundnodes,info);
7526
FindNewBoundaries(data,bound,boundnodes,eg->boundbound[3*l+2],2,info);
7527
}
7528
}
7529
free_Ivector(boundnodes,1,data->noknots);
7530
7531
return(0);
7532
}
7533
7534
7535
void NodesToBoundaryChain(struct FemType *data,struct BoundaryType *bound,
7536
int *bcinds,int *bctags,int nbc,int bccount,
7537
int info)
7538
{
7539
int i,j,k,l,sideelemtype,sideelemtype2,elemind,elemind2,sideelem,sameelem;
7540
int sideind[MAXNODESD1],sideind2[MAXNODESD1],elemsides,side,hit,same,minelemtype;
7541
int sidenodes,sidenodes2,elemtype,elemdim,sideelements,material;
7542
int *possible=NULL,**invtopo=NULL;
7543
int noelements,maxpossible,noknots,twiceelem,sideelemdim;
7544
int elemhits,bci;
7545
7546
7547
if(info) printf("Creating boundary elements from boundary nodes\n");
7548
7549
for(j=0;j < MAXBOUNDARIES;j++)
7550
bound[j].created = FALSE;
7551
for(j=0;j < MAXBOUNDARIES;j++)
7552
bound[j].nosides = 0;
7553
7554
noelements = data->noelements;
7555
noknots = data->noknots;
7556
7557
sideelements = nbc - bccount;
7558
printf("Expected number of BC elements: %d\n",sideelements);
7559
7560
AllocateBoundary(bound,sideelements);
7561
7562
/* Calculate how may times a node appears */
7563
possible = Ivector(1,noknots);
7564
for(i=1;i<=noknots;i++) possible[i] = 0;
7565
for(elemind=1;elemind <= data->noelements;elemind++) {
7566
for(i=0;i<data->elementtypes[elemind]%100;i++) {
7567
j = data->topology[elemind][i];
7568
possible[j] += 1;
7569
}
7570
}
7571
7572
j = 1;
7573
maxpossible = possible[1];
7574
for(i=1;i<=noknots;i++) {
7575
if(maxpossible < possible[i]) {
7576
maxpossible = possible[i];
7577
j = i;
7578
}
7579
}
7580
if(info) printf("Node %d belongs to maximum of %d elements\n",j,maxpossible);
7581
7582
/* Make a table showing to which elements a node belongs to
7583
Include only the potential parents which are not to be moved to BCs. */
7584
invtopo = Imatrix(1,noknots,1,maxpossible);
7585
7586
for(i=1;i<=noknots;i++)
7587
for(j=1;j<=maxpossible;j++)
7588
invtopo[i][j] = 0;
7589
7590
for(elemind=1;elemind <= data->noelements;elemind++) {
7591
elemtype = data->elementtypes[elemind];
7592
for(i=0;i<elemtype%100;i++) {
7593
k = data->topology[elemind][i];
7594
for(l=1;invtopo[k][l];l++); /* Yes, this is really ok. We look for unset entry. */
7595
invtopo[k][l] = elemind;
7596
}
7597
}
7598
7599
sideelem = 0;
7600
sameelem = 0;
7601
twiceelem = 0;
7602
7603
/* These are here by construction because we are looking for a chain of nodes
7604
and trying to create 202 elements of them! */
7605
sidenodes = 2;
7606
sideelemtype = 202;
7607
7608
for(bci=1;bci<nbc;bci++) {
7609
7610
same = FALSE;
7611
7612
if( bctags[bci] != bctags[bci+1] ) continue;
7613
7614
sideind[0] = bcinds[bci];
7615
sideind[1] = bcinds[bci+1];
7616
material = bctags[bci];
7617
7618
elemhits = 0;
7619
7620
/* Go through potential parents elements using the inverse topology */
7621
for(l=1;l<=maxpossible;l++) {
7622
elemind2 = invtopo[sideind[0]][l];
7623
7624
if(!elemind2) continue;
7625
7626
elemtype = data->elementtypes[elemind2];
7627
hit = 0;
7628
for(i=0;i<sidenodes;i++)
7629
for(j=0;j<elemtype%100;j++)
7630
if(sideind[i] == data->topology[elemind2][j]) hit++;
7631
7632
/* We must have all hits to have a chance of finding bc */
7633
if(hit < sidenodes) continue;
7634
7635
elemhits++;
7636
7637
/* Now find on which side the bc is */
7638
for(side=0;side<3;side++) {
7639
GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2);
7640
if( sideelemtype2 != sideelemtype ) printf("This should not happen!\n");
7641
7642
hit = 0;
7643
for(i=0;i<sidenodes;i++)
7644
for(j=0;j<sidenodes;j++)
7645
if(sideind[i] == sideind2[j]) hit++;
7646
7647
if(hit < sidenodes) continue;
7648
7649
if(same) {
7650
/* Ok, we found the other parent for this already */
7651
sameelem += 1;
7652
bound->parent2[sideelem] = elemind2;
7653
bound->side2[sideelem] = side;
7654
goto foundtwo;
7655
}
7656
else {
7657
/* We haven't found parents for this bc elements yet */
7658
sideelem += 1;
7659
same = TRUE;
7660
bound->parent[sideelem] = elemind2;
7661
bound->side[sideelem] = side;
7662
bound->parent2[sideelem] = 0;
7663
bound->side2[sideelem] = 0;
7664
bound->types[sideelem] = material;
7665
if(sidenodes == 2) {
7666
if((sideind[0]-sideind[1])*(sideind2[0]-sideind2[1])<0)
7667
bound->normal[sideelem] = -1;
7668
}
7669
}
7670
}
7671
}
7672
foundtwo:
7673
continue;
7674
}
7675
7676
if(twiceelem) printf("Found %d sides that were multiply given\n",twiceelem);
7677
if(sameelem) printf("Found %d side elements that have two parents.\n",sameelem);
7678
7679
7680
if(sideelem == sideelements) {
7681
printf("Found correctly %d side elements.\n",sideelem);
7682
}
7683
else {
7684
printf("Found %d side elements, could have found %d\n",sideelem,sideelements);
7685
}
7686
7687
bound->nosides = sideelem;
7688
7689
free_Ivector(possible,1,noknots);
7690
free_Imatrix(invtopo,1,noknots,1,maxpossible);
7691
7692
return;
7693
}
7694
7695
7696
7697
7698
int FindPeriodicNodes(struct FemType *data,int periodicdim[],int info)
7699
{
7700
int i,j,i2,j2,dim;
7701
int noknots,hit,tothits;
7702
int *topbot=NULL,*indxper=NULL;
7703
int botn,topn,*revindtop=NULL,*revindbot=NULL;
7704
Real eps,dist,dx,dy,dz,coordmax,coordmin;
7705
Real *coord=NULL,*toparr=NULL,*botarr=NULL,epsmin;
7706
7707
7708
if(data->dim < 3) periodicdim[2] = 0;
7709
if(!periodicdim[0] && !periodicdim[1] && !periodicdim[2]) return(1);
7710
7711
if(data->periodicexist) {
7712
printf("FindPeriodicNodes: Subroutine is called for second time?\n");
7713
return(2);
7714
}
7715
7716
noknots = data->noknots;
7717
tothits = 0;
7718
7719
data->periodicexist = TRUE;
7720
indxper = Ivector(1,noknots);
7721
data->periodic = indxper;
7722
topbot = Ivector(1,noknots);
7723
7724
7725
for(i=1;i<=noknots;i++)
7726
indxper[i] = i;
7727
7728
for(dim=1;dim<=3;dim++) {
7729
if(!periodicdim[dim-1]) continue;
7730
7731
if(info) printf("Finding periodic nodes in direction %d\n",dim);
7732
7733
if(dim==1) coord = data->x;
7734
else if(dim==2) coord = data->y;
7735
else coord = data->z;
7736
7737
coordmax = coordmin = coord[1];
7738
7739
for(i=1;i<=data->noknots;i++) {
7740
if(coordmax < coord[i]) coordmax = coord[i];
7741
if(coordmin > coord[i]) coordmin = coord[i];
7742
}
7743
7744
if(info) printf("Coordinate in dimension %d is at the interval [%.3lg, %.3lg]\n",
7745
dim,coordmin,coordmax);
7746
7747
if(coordmax-coordmin < 1.0e-10) continue;
7748
eps = 1.0e-5 * (coordmax-coordmin);
7749
7750
topn = botn = 0;
7751
for(i=1;i<=data->noknots;i++) {
7752
if(fabs(coord[i]-coordmax) < eps) {
7753
topn++;
7754
topbot[i] = topn;
7755
}
7756
else if(fabs(coord[i] - coordmin) < eps) {
7757
botn++;
7758
topbot[i] = -botn;
7759
}
7760
else {
7761
topbot[i] = 0;
7762
}
7763
}
7764
7765
if(topn != botn) {
7766
printf("There should be equal number of top and bottom nodes (%d vs. %d)!\n",topn,botn);
7767
return(3);
7768
}
7769
else {
7770
if(info) printf("Looking for %d periodic nodes\n",topn);
7771
}
7772
7773
toparr = Rvector(1,topn);
7774
botarr = Rvector(1,botn);
7775
revindtop = Ivector(1,topn);
7776
revindbot = Ivector(1,botn);
7777
7778
topn = botn = 0;
7779
for(i=1;i<=noknots;i++) {
7780
j = topbot[i];
7781
if(j > 0) {
7782
topn++;
7783
revindtop[topn] = i;
7784
}
7785
else if(j < 0) {
7786
j = abs(j);
7787
botn++;
7788
revindbot[botn] = i;
7789
}
7790
}
7791
7792
if(data->dim == 2) {
7793
for(i=1;i<=botn;i++) {
7794
j = revindbot[i];
7795
hit = FALSE;
7796
for(i2=1;i2<=topn;i2++) {
7797
j2 = revindtop[i2];
7798
if(dim == 1)
7799
dist = fabs(data->y[j] - data->y[j2]);
7800
else
7801
dist = fabs(data->x[j] - data->x[j2]);
7802
if(dist < eps) {
7803
hit = TRUE;
7804
goto hit2d;
7805
}
7806
}
7807
7808
hit2d:
7809
if(hit) {
7810
tothits++;
7811
if(indxper[j] == j) indxper[j2] = j;
7812
else if(indxper[indxper[j]]==indxper[j]) {
7813
indxper[j2] = indxper[j];
7814
}
7815
else {
7816
printf("unknown 2d case!\n");
7817
}
7818
}
7819
else {
7820
printf("Couldn't find a periodic counterpart for node %d at [%.3lg %.3lg]]\n",
7821
j,data->x[j],data->y[j]);
7822
}
7823
}
7824
}
7825
else if(data->dim == 3) {
7826
dx = dy = dz = 0.0;
7827
for(i=1;i<=botn;i++) {
7828
j = revindbot[i];
7829
hit = FALSE;
7830
epsmin = coordmax - coordmin;
7831
7832
for(i2=1;i2<=topn;i2++) {
7833
j2 = revindtop[i2];
7834
if(dim == 1) {
7835
dy = data->y[j] - data->y[j2];
7836
dz = data->z[j] - data->z[j2];
7837
}
7838
else if(dim == 2) {
7839
dx = data->x[j] - data->x[j2];
7840
dz = data->z[j] - data->z[j2];
7841
}
7842
else {
7843
dx = data->x[j] - data->x[j2];
7844
dy = data->y[j] - data->y[j2];
7845
}
7846
if(dx*dx+dy*dy+dz*dz < eps*eps) {
7847
hit = TRUE;
7848
goto hit3d;
7849
}
7850
}
7851
7852
hit3d:
7853
if(hit) {
7854
tothits++;
7855
indxper[j2] = indxper[j];
7856
}
7857
else {
7858
printf("The periodic counterpart for node %d was not found!\n",j);
7859
}
7860
}
7861
}
7862
7863
free_Rvector(toparr,1,topn);
7864
free_Rvector(botarr,1,botn);
7865
free_Ivector(revindtop,1,topn);
7866
free_Ivector(revindbot,1,botn);
7867
}
7868
7869
if(info) printf("Found all in all %d periodic nodes.\n",tothits);
7870
7871
free_Ivector(topbot,1,noknots);
7872
7873
return(0);
7874
}
7875
7876
7877
7878
7879
int FindPeriodicParents(struct FemType *data,struct BoundaryType *bound,int info)
7880
{
7881
int i,j,k,k2,l,l2,totsides,newsides,sidenodes,sideelemtype,side;
7882
int noknots,maxhits,nodes,hits,hits2,targets,mappings,targetnode;
7883
int parent,parent2,sideind[MAXNODESD1],sideind2[MAXNODESD1];
7884
int **periodicparents=NULL, *periodichits=NULL,*periodictarget=NULL,*indexper=NULL;
7885
7886
totsides = 0;
7887
newsides = 0;
7888
targets = 0;
7889
parent2 = 0;
7890
7891
if(info) printf("Finding secondary periodic parents for boundary elements\n");
7892
7893
if(!data->periodicexist) {
7894
printf("FindPeriodicParents: Periodic nodes are not defined\n");
7895
return(2);
7896
}
7897
7898
indexper = data->periodic;
7899
7900
/* Set pointers that point to the periodic nodes */
7901
noknots = data->noknots;
7902
periodictarget = Ivector(1,noknots);
7903
for(i=1;i<=noknots;i++)
7904
periodictarget[i] = 0;
7905
7906
mappings = 0;
7907
for(i=1;i<=noknots;i++) {
7908
j = indexper[i];
7909
if( j != i) {
7910
mappings++;
7911
periodictarget[j] = i;
7912
}
7913
}
7914
7915
if(0) for(i=1;i<=noknots;i++)
7916
printf("indexes(%d) : %d %d\n",i,indexper[i],periodictarget[i]);
7917
7918
7919
if(info) printf("Number of potential periodic mappings is %d\n",mappings);
7920
for(i=1;i<=noknots;i++)
7921
if(periodictarget[i]) targets++;
7922
if(info) printf("Number of potential periodic targets is %d\n",targets);
7923
7924
7925
/* Vector telling how many elements are associated with the periodic nodes */
7926
maxhits = 0;
7927
periodichits = Ivector(1,noknots);
7928
for(i=1;i<=noknots;i++)
7929
periodichits[i] = 0;
7930
7931
/* Create the matrix telling which elements are associated with the periodic nodes */
7932
setparents:
7933
for(j=1;j <= data->noelements;j++) {
7934
nodes = data->elementtypes[j] % 100;
7935
for(i=0;i<nodes;i++) {
7936
k = data->topology[j][i];
7937
if( k != indexper[k] ) {
7938
periodichits[k] += 1;
7939
if( maxhits > 0 ) {
7940
periodicparents[k][periodichits[k]] = j;
7941
}
7942
}
7943
}
7944
}
7945
7946
if( maxhits == 0 ) {
7947
for(i=1;i<=noknots;i++)
7948
maxhits = MAX( maxhits, periodichits[i] );
7949
7950
printf("Maximum number of elements associated with periodic nodes is %d\n",maxhits);
7951
periodicparents = Imatrix(1,noknots,1,maxhits);
7952
for(i=1;i<=noknots;i++) {
7953
periodichits[i] = 0;
7954
for(j=1;j<=maxhits;j++)
7955
periodicparents[i][j] = 0;
7956
}
7957
goto setparents;
7958
}
7959
7960
for(j=0;j<MAXBOUNDARIES;j++) {
7961
if(!bound[j].created) continue;
7962
if(!bound[j].nosides) continue;
7963
7964
for(i=1;i<=bound[j].nosides;i++) {
7965
7966
/* If secondary parent already set skip */
7967
if(bound[j].parent2[i]) continue;
7968
7969
parent = bound[j].parent[i];
7970
if(0) printf("1st parent %d\n",parent);
7971
7972
side = bound[j].side[i];
7973
7974
GetElementSide(parent,side,1,data,sideind,&sideelemtype);
7975
sidenodes = sideelemtype % 100;
7976
7977
/* Some node must be periodic target and others either target or mapped nodes */
7978
hits = hits2 = 0;
7979
for(k=0;k<sidenodes;k++) {
7980
l = sideind[k];
7981
if( periodictarget[l] )
7982
hits++;
7983
else if(indexper[l] != l)
7984
hits2++;
7985
}
7986
if(!hits || hits + hits2 < sidenodes) continue;
7987
7988
if(0) printf("Trying to find other parent for boundary %d and parent %d\n",
7989
bound[j].types[i],parent);
7990
if(0) printf("hits = %d %d %d\n",hits,hits2,sidenodes);
7991
7992
totsides++;
7993
7994
/* The parent is the one element that has exactly the same set of periodic nodes */
7995
for(l=0;l<sidenodes;l++) {
7996
targetnode = periodictarget[sideind[l]];
7997
if(!targetnode) continue;
7998
7999
for(l2=1;l2<=periodichits[targetnode];l2++) {
8000
int side,elemtype,elemsides,sideelemtype2;
8001
8002
parent2 = periodicparents[targetnode][l2];
8003
if(parent == parent2) continue;
8004
8005
elemtype = data->elementtypes[parent2];
8006
elemsides = GetElementFaces(elemtype);
8007
8008
for(side=0;side<elemsides;side++) {
8009
GetElementSide(parent2,side,1,data,sideind2,&sideelemtype2);
8010
if( sideelemtype != sideelemtype2 ) continue;
8011
8012
hits = 0;
8013
for(k=0;k<sidenodes;k++) {
8014
for(k2=0;k2<sidenodes;k2++) {
8015
if( indexper[sideind[k]] == indexper[sideind2[k2]]) {
8016
hits++;
8017
break;
8018
}
8019
}
8020
}
8021
if(hits == sidenodes) goto found;
8022
}
8023
}
8024
}
8025
8026
found:
8027
if(hits == sidenodes) {
8028
newsides++;
8029
if(0) printf("Parents joined by boundary element: %d %d\n",parent,parent2);
8030
bound[j].parent2[i] = -parent2;
8031
}
8032
else {
8033
printf("Could not find a periodic counterpart: %d/%d/%d\n",j,i,parent);
8034
printf("ind = %d ",sideind[0]);
8035
for(k=1;k<sidenodes;k++)
8036
printf("%d ",sideind[k]);
8037
printf("\n");
8038
}
8039
}
8040
}
8041
8042
free_Ivector(periodictarget,1,noknots);
8043
free_Ivector(periodichits,1,noknots);
8044
free_Imatrix(periodicparents,1,noknots,1,maxhits);
8045
8046
if(info) printf("Found %d secondary parents for %d potential sides.\n",newsides,totsides);
8047
return(0);
8048
}
8049
8050
8051
8052
8053
int CreateBoundaryLayer(struct FemType *data,struct BoundaryType *bound,
8054
int nolayers, int *layerbounds, int *layernumber,
8055
Real *layerratios, Real *layerthickness, int *layerparents,
8056
int maxfilters, Real layereps, int info)
8057
/* Create Boundary layers that may be used to solve accurately fluid
8058
flow problems and similar equations. */
8059
{
8060
int i,j,k,l,m,n,i2,i3,nonodes,maxbc,newbc;
8061
int noknots,noelements,elemindx,nodeindx,elemtype;
8062
int oldnoknots,oldnoelements,maxelemtype,oldmaxnodes;
8063
int nonewnodes,nonewelements,dolayer,dim,order,midpoints;
8064
int checkmaterials,parent,parent2,use2,second;
8065
Real dx,dy,ds,ratio,q,p,rectfactor;
8066
Real *newx=NULL,*newy=NULL,*newz=NULL,*oldx=NULL,*oldy=NULL,*elemwidth=NULL;
8067
Real e1x,e1y,e2x,e2y;
8068
int sideelemtype,ind[MAXNODESD2],sidebc[MAXNODESD1];
8069
int *layernode=NULL,*newelementtypes=NULL,**newtopo=NULL,**oldtopo=NULL;
8070
int *topomap=NULL,*newmaterial=NULL,*herit=NULL,*inside=NULL,*nonlin=NULL;
8071
int endbcs, *endparents=NULL, *endtypes=NULL, *endnodes=NULL, *endnodes2=NULL, *endneighbours=NULL;
8072
8073
if(0) printf("maxfilters=%d layereps=%.3e\n",maxfilters,layereps);
8074
8075
if(!maxfilters) maxfilters = 1000;
8076
if(layereps < 1.0e-20) layereps = 1.0e-3;
8077
rectfactor = 1.0e2;
8078
midpoints = FALSE;
8079
order = 1;
8080
dim = data->dim;
8081
8082
maxelemtype = GetMaxElementType(data);
8083
if(maxelemtype > 409) {
8084
printf("Subroutine implemented only up to 2nd degree in 2D!\n");
8085
bigerror("Cannot continue");
8086
}
8087
8088
if(info) printf("Largest elementtype is %d\n",maxelemtype);
8089
8090
second = FALSE;
8091
checkmaterials = FALSE;
8092
for(k=0;k<nolayers;k++)
8093
if(layerparents[k]) checkmaterials = TRUE;
8094
8095
8096
omstart:
8097
8098
oldnoelements = noelements = data->noelements;
8099
oldnoknots = noknots = data->noknots;
8100
oldmaxnodes = data->maxnodes;
8101
8102
layernode = Ivector(1,oldnoknots);
8103
for(i=1;i<=oldnoknots;i++) layernode[i] = 0;
8104
8105
8106
/* Go through all the boundaries with boundary layer definitions and compute
8107
the number of new nodes and new elements. */
8108
nonewnodes = 0;
8109
nonewelements = 0;
8110
maxbc = 0;
8111
8112
/* Go through the layers and check which ones are active */
8113
for(j=0;j<MAXBOUNDARIES;j++) {
8114
if(!bound[j].created) continue;
8115
8116
for(i=1;i<=bound[j].nosides;i++) {
8117
dolayer = FALSE;
8118
parent = bound[j].parent[i];
8119
use2 = FALSE;
8120
if(bound[j].types[i] > maxbc) maxbc = bound[j].types[i];
8121
8122
for(k=0;k<nolayers;k++) {
8123
8124
if(bound[j].types[i] == layerbounds[k]) {
8125
if(checkmaterials) {
8126
if(layerparents[k] < 0) continue;
8127
8128
if(data->material[parent] == layerparents[k])
8129
dolayer = k + 1;
8130
else if((parent = bound[j].parent2[i])) {
8131
if(data->material[parent] == layerparents[k]) {
8132
use2 = TRUE;
8133
dolayer = k + 1;
8134
}
8135
}
8136
}
8137
else {
8138
dolayer = k + 1;
8139
}
8140
}
8141
}
8142
8143
if(!dolayer) continue;
8144
8145
8146
/* We have found an boundary element to extrude */
8147
if(use2)
8148
GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],
8149
data,ind,&sideelemtype);
8150
else
8151
GetElementSide(parent,bound[j].side[i],bound[j].normal[i],
8152
data,ind,&sideelemtype);
8153
8154
nonewelements += layernumber[dolayer-1];
8155
8156
midpoints = FALSE;
8157
if(sideelemtype == 202) {
8158
order = 1;
8159
}
8160
else if(sideelemtype == 203) {
8161
order = 2;
8162
if(maxelemtype > 408) midpoints = TRUE;
8163
}
8164
8165
for(l=0;l<sideelemtype%100;l++) {
8166
8167
/* No layer has yet been created for this node */
8168
if(!layernode[ind[l]]) {
8169
8170
layernode[ind[l]] = -(noknots + nonewnodes);
8171
8172
if(l < sideelemtype/100 || midpoints)
8173
nonewnodes += order * layernumber[dolayer-1];
8174
else
8175
nonewnodes += layernumber[dolayer-1];
8176
}
8177
else {
8178
layernode[ind[l]] = abs(layernode[ind[l]]);
8179
}
8180
}
8181
}
8182
}
8183
8184
if(!nonewelements) {
8185
if(info) printf("Found no active boundary layers!\n");
8186
return(0);
8187
}
8188
8189
/* For higher order elements remove the middlenodes from the list of cornernodes */
8190
if(maxelemtype%100 > 4) {
8191
for(j=1;j<=noelements;j++) {
8192
elemtype = data->elementtypes[j];
8193
for(i=elemtype/100;i<elemtype%100;i++) {
8194
k = data->topology[j][i];
8195
layernode[k] = abs(layernode[k]);
8196
}
8197
}
8198
}
8199
8200
8201
/* Negative indexed means that the node is an end node of the newly created boundary */
8202
endbcs = 0;
8203
for(i=1;i<=noknots;i++)
8204
if(layernode[i] < 0) endbcs++;
8205
8206
if(endbcs) {
8207
endparents = Ivector(1,endbcs);
8208
endtypes = Ivector(1,endbcs);
8209
endnodes = Ivector(1,endbcs);
8210
endnodes2 = Ivector(1,endbcs);
8211
8212
endneighbours = Ivector(1,2*endbcs);
8213
for(i=1;i<=endbcs;i++)
8214
endparents[i] = endtypes[i] = endnodes[i] = endnodes2[i] = 0;
8215
8216
endbcs = 0;
8217
for(i=1;i<=noknots;i++) {
8218
if(layernode[i] < 0) {
8219
endbcs++;
8220
endparents[endbcs] = i;
8221
}
8222
}
8223
}
8224
8225
8226
/* Check if the new boundary is already connected to some one,
8227
however it must be different from the extruded boundary */
8228
for(i2=1;i2<=endbcs;i2++) {
8229
for(j=0;j<MAXBOUNDARIES;j++) {
8230
if(!bound[j].created) continue;
8231
8232
for(i=1;i<=bound[j].nosides;i++) {
8233
8234
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8235
data,ind,&sideelemtype);
8236
8237
/* Check that the node is one of the single nodes */
8238
dolayer = FALSE;
8239
for(i3=0;i3<sideelemtype%100;i3++)
8240
if(ind[i3] == endparents[i2]) {
8241
dolayer = TRUE;
8242
break;
8243
}
8244
if(!dolayer) continue;
8245
8246
/* First check that the found boundary has a correct parent material */
8247
dolayer = FALSE;
8248
if(checkmaterials) {
8249
for(k=0;k<nolayers;k++) {
8250
if(layerparents[k] < 0) continue;
8251
parent = bound[j].parent[i];
8252
if(data->material[parent] == layerparents[k])
8253
dolayer = TRUE;
8254
else if((parent = bound[j].parent2[i])) {
8255
if(data->material[parent] == layerparents[k]) {
8256
dolayer = TRUE;
8257
}
8258
}
8259
}
8260
}
8261
if(!dolayer) continue;
8262
8263
/* Finally check that this is not one of the extruded boundaries */
8264
dolayer = FALSE;
8265
for(k=0;k<nolayers;k++) {
8266
if(layerparents[k] < 0) continue;
8267
if(bound[j].types[i] == layerbounds[k]) dolayer = TRUE;
8268
}
8269
if(dolayer) {
8270
endneighbours[2*i2-1] = ind[1-i3];
8271
continue;
8272
}
8273
8274
endtypes[i2] = bound[j].types[i];
8275
dx = fabs(data->x[ind[0]] - data->x[ind[1]]);
8276
dy = fabs(data->y[ind[0]] - data->y[ind[1]]);
8277
8278
if(dx < rectfactor * dy && dy < rectfactor * dx) {
8279
endnodes[i2] = ind[i3];
8280
if(sideelemtype%100 > 2) endnodes2[i2] = ind[2];
8281
endneighbours[2*i2] = ind[1-i3];
8282
}
8283
8284
if(info) printf("Found an existing boundary %d for the single node %d %d\n",
8285
bound[j].types[i],endparents[i2],endnodes[i2]);
8286
8287
goto foundbc;
8288
}
8289
}
8290
8291
foundbc:
8292
8293
if(!endtypes[i2]) {
8294
maxbc++;
8295
endtypes[i2] = maxbc;
8296
}
8297
}
8298
8299
8300
/* Find the first unused bc */
8301
for(j=0;j<MAXBOUNDARIES;j++)
8302
if(!bound[j].created) {
8303
newbc = j;
8304
bound[newbc].nosides = 0;
8305
break;
8306
}
8307
8308
/* Find the maximum of layers */
8309
i = 0;
8310
for(k=0;k<nolayers;k++)
8311
if(layernumber[k] > i) i = layernumber[k];
8312
8313
if(endbcs) {
8314
if(info) {
8315
printf("Allocating for additional %d boundary elements into bc %d.\n",
8316
bound[newbc].nosides,newbc);
8317
}
8318
AllocateBoundary(&bound[newbc],i*endbcs);
8319
bound[newbc].created = FALSE;
8320
bound[newbc].nosides = 0;
8321
}
8322
8323
8324
/* The size of new mesh */
8325
noknots = data->noknots + nonewnodes;
8326
noelements = data->noelements + nonewelements;
8327
8328
oldnoelements = data->noelements;
8329
oldnoknots = data->noknots;
8330
8331
if(info) {
8332
printf("Creating additional %d elements and %d nodes.\n",nonewelements,nonewnodes);
8333
printf("Boundary layer mesh has %d elements and %d nodes.\n",noelements,noknots);
8334
}
8335
8336
/* there will be more nodes if the original mesh consists of triangles */
8337
if(maxelemtype <= 303)
8338
data->maxnodes = 4;
8339
else if(maxelemtype == 306)
8340
data->maxnodes = 8;
8341
8342
/* Allocate more space for the enlarged data set */
8343
newtopo = Imatrix(1,noelements,0,data->maxnodes-1);
8344
newmaterial = Ivector(1,noelements);
8345
newelementtypes = Ivector(1,noelements);
8346
newx = Rvector(1,noknots);
8347
newy = Rvector(1,noknots);
8348
newz = Rvector(1,noknots);
8349
for(i=1;i<=noknots;i++) newz[i] = 0.0;
8350
8351
elemwidth = Rvector(1,nonewelements);
8352
for(i=1;i<=nonewelements;i++) elemwidth[i] = 0.0;
8353
8354
herit = Ivector(1,noknots);
8355
for(i=1;i<=oldnoknots;i++) herit[i] = i;
8356
for(i=oldnoknots+1;i<=noknots;i++) herit[i] = 0;
8357
8358
8359
/* Set the old topology */
8360
for(j=1;j<=data->noelements;j++) {
8361
newmaterial[j] = data->material[j];
8362
newelementtypes[j] = data->elementtypes[j];
8363
for(i=0;i<data->elementtypes[j]%100;i++)
8364
newtopo[j][i] = data->topology[j][i];
8365
}
8366
8367
/* Set the old nodes */
8368
for(i=1;i<=data->noknots;i++) {
8369
newx[i] = data->x[i];
8370
newy[i] = data->y[i];
8371
}
8372
8373
topomap = Ivector(1,noknots);
8374
for(i=1;i<=noknots;i++) topomap[i] = i;
8375
8376
inside = Ivector(1,noelements);
8377
for(i=1;i<=noelements;i++) inside[i] = FALSE;
8378
8379
/* Set the new node topology and nodes */
8380
elemindx = data->noelements;
8381
for(j=0;j<MAXBOUNDARIES;j++) {
8382
if(!bound[j].created) continue;
8383
8384
for(i=1;i<=bound[j].nosides;i++) {
8385
8386
dolayer = FALSE;
8387
parent = bound[j].parent[i];
8388
parent2 = bound[j].parent2[i];
8389
use2 = FALSE;
8390
8391
for(k=0;k<nolayers;k++) {
8392
if(bound[j].types[i] == layerbounds[k]) {
8393
if(checkmaterials) {
8394
if(layerparents[k] < 0) continue;
8395
8396
if(data->material[parent] == layerparents[k]) {
8397
dolayer = k + 1;
8398
}
8399
else if(parent2) {
8400
l = parent;
8401
parent = parent2;
8402
parent2 = l;
8403
if(data->material[parent] == layerparents[k]) {
8404
use2 = TRUE;
8405
dolayer = k + 1;
8406
}
8407
}
8408
}
8409
else dolayer = k + 1;
8410
}
8411
}
8412
8413
8414
if(!dolayer) continue;
8415
8416
if(use2)
8417
GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],
8418
data,ind,&sideelemtype);
8419
else
8420
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8421
data,ind,&sideelemtype);
8422
8423
inside[parent] = 1;
8424
8425
if(sideelemtype == 202)
8426
order = 1;
8427
else if(sideelemtype == 203)
8428
order = 2;
8429
8430
/* Check if some node should result into additional BC */
8431
for(i2=0;i2<sideelemtype%100;i2++) {
8432
sidebc[i2] = FALSE;
8433
if(i2 < 2 && layernode[ind[i2]] < 0) {
8434
layernode[ind[i2]] = abs(layernode[ind[i2]]);
8435
sidebc[i2] = TRUE;
8436
}
8437
}
8438
8439
/* Define the normal of the surface */
8440
dy = -(data->x[ind[1]] - data->x[ind[0]]);
8441
dx = data->y[ind[1]] - data->y[ind[0]];
8442
ds = sqrt(dx*dx+dy*dy);
8443
dx /= ds;
8444
dy /= ds;
8445
8446
n = layernumber[dolayer-1];
8447
ds = -layerthickness[dolayer-1];
8448
8449
for(l=0;l < n;l++) {
8450
elemindx++;
8451
8452
newmaterial[elemindx] = data->material[parent];
8453
inside[elemindx] = 1;
8454
8455
if(n <= 1 || fabs(layerratios[dolayer-1]-1.0) < 0.001) {
8456
q = (1.0*(l+1))/n;
8457
elemwidth[elemindx-oldnoelements] = ds / n;
8458
}
8459
else {
8460
ratio = pow(layerratios[dolayer-1],-1./(n-1.));
8461
q = (1.- pow(ratio,(Real)(l+1))) / (1.-pow(ratio,(Real)(n)));
8462
p = (1.- pow(ratio,(Real)(l))) / (1.-pow(ratio,(Real)(n)));
8463
elemwidth[elemindx-oldnoelements] = (q-p) * ds;
8464
}
8465
8466
8467
for(m=0;m<sideelemtype%100;m++) {
8468
8469
/* Make the possible additional BC appearing at side of the BL */
8470
if(sidebc[m]) {
8471
8472
bound[newbc].nosides += 1;
8473
i2 = bound[newbc].nosides;
8474
bound[newbc].parent[i2] = elemindx;
8475
bound[newbc].parent2[i2] = 0;
8476
bound[newbc].side[i2] = 3 - 2*m;
8477
bound[newbc].side2[i2] = 0;
8478
8479
for(i3=1;i3<=endbcs;i3++)
8480
if(ind[m] == endparents[i3]) {
8481
bound[newbc].types[i2] = endtypes[i3];
8482
endneighbours[2*i3-1] = layernode[ind[m]] + 1;
8483
break;
8484
}
8485
}
8486
8487
/* Set the node coordinates */
8488
if(m < 2) {
8489
nodeindx = layernode[ind[m]] + order*(l+1);
8490
}
8491
else {
8492
nodeindx = layernode[ind[m]] + (1+midpoints)*(l+1);
8493
}
8494
e1x = dx * q * ds;
8495
e1y = dy * q * ds;
8496
8497
/* Compute the normal of a joined node */
8498
if(herit[nodeindx] != 0) {
8499
8500
e2x = newx[nodeindx] - data->x[ind[m]];
8501
e2y = newy[nodeindx] - data->y[ind[m]];
8502
8503
p = (e1x*e2x + e1y*e2y)/(sqrt(e1x*e1x+e1y*e1y)*sqrt(e2x*e2x+e2y*e2y));
8504
8505
newx[nodeindx] += e1x - p * e2x;
8506
newy[nodeindx] += e1y - p * e2y;
8507
}
8508
else {
8509
herit[nodeindx] = ind[m];
8510
newx[nodeindx] = data->x[ind[m]] + e1x;
8511
newy[nodeindx] = data->y[ind[m]] + e1y;
8512
}
8513
}
8514
8515
/* Create the bulk elements */
8516
if(l==0) {
8517
newtopo[elemindx][3] = ind[0];
8518
newtopo[elemindx][2] = ind[1];
8519
if(order == 2) newtopo[elemindx][6] = ind[2];
8520
}
8521
else {
8522
newtopo[elemindx][3] = layernode[ind[0]] + order*l;
8523
newtopo[elemindx][2] = layernode[ind[1]] + order*l;
8524
if(order == 2) newtopo[elemindx][6] = layernode[ind[2]] + (midpoints+1)*l;
8525
}
8526
newtopo[elemindx][0] = layernode[ind[0]] + order*(l+1);
8527
newtopo[elemindx][1] = layernode[ind[1]] + order*(l+1);
8528
8529
if(order == 2) {
8530
newtopo[elemindx][7] = layernode[ind[0]] + order*l+1;
8531
newtopo[elemindx][5] = layernode[ind[1]] + order*l+1;
8532
newtopo[elemindx][4] = layernode[ind[2]] + (midpoints+1)*(l+1);
8533
if(midpoints) newtopo[elemindx][8] = layernode[ind[2]] + 2*l+1;
8534
}
8535
8536
if(order == 1) {
8537
newelementtypes[elemindx] = 404;
8538
}
8539
else if(midpoints) {
8540
newelementtypes[elemindx] = 409;
8541
}
8542
else {
8543
newelementtypes[elemindx] = 408;
8544
}
8545
8546
8547
if(l == n-1 && parent2) {
8548
8549
elemtype = data->elementtypes[parent2];
8550
inside[parent2] = 2;
8551
8552
for(i2=0;i2<elemtype%100;i2++) {
8553
for(i3=0;i3<sideelemtype%100;i3++) {
8554
if(data->topology[parent2][i2] == ind[i3]) {
8555
if(i3 < 2) {
8556
topomap[ind[i3]] = layernode[ind[i3]] + order * n;
8557
}
8558
else {
8559
topomap[ind[i3]] = layernode[ind[i3]] + (midpoints+1) * n;
8560
}
8561
}
8562
}
8563
}
8564
}
8565
}
8566
8567
/* Finally set the BC to point to the new boundary */
8568
if(use2) {
8569
bound[j].side2[i] = 0;
8570
bound[j].parent2[i] = elemindx;
8571
}
8572
else {
8573
bound[j].side[i] = 0;
8574
bound[j].parent[i] = elemindx;
8575
}
8576
}
8577
}
8578
8579
8580
{
8581
int *inside2;
8582
inside2 = Ivector(1,noknots);
8583
for(i=1;i<=noknots;i++) inside2[i] = 0;
8584
8585
/* Put a marker to all nodes that belong to elements that are on the outside */
8586
for(j=1;j<=noelements;j++) {
8587
if(inside[j] == 2) {
8588
elemtype = data->elementtypes[j];
8589
for(i=0;i<elemtype/100;i++) {
8590
inside2[newtopo[j][i]] = TRUE;
8591
}
8592
}
8593
}
8594
8595
/* Now check other outside elements that have at least 2 nodes that are also on outside */
8596
for(j=1;j<=noelements;j++) {
8597
if(!inside[j]) {
8598
elemtype = data->elementtypes[j];
8599
k = 0;
8600
for(i=0;i<elemtype/100;i++)
8601
if(inside2[newtopo[j][i]]) k++;
8602
if(k > 1) inside[j] = 2;
8603
}
8604
}
8605
free_Ivector(inside2,1,noknots);
8606
8607
/* Still, go through all elements and if they are not on the list of
8608
active materials assume them outside */
8609
if(checkmaterials) {
8610
for(j=1;j<=oldnoelements;j++) {
8611
dolayer = FALSE;
8612
for(k=0;k<nolayers;k++)
8613
if(data->material[j] == layerparents[k]) dolayer = TRUE;
8614
8615
if(!dolayer) {
8616
if(inside[j] == 1) printf("Element %d of material %d should be in the inside\n",
8617
j,data->material[j]);
8618
inside[j] = 2;
8619
}
8620
}
8621
}
8622
8623
/* And finally remap the nodes that are on the outside */
8624
for(j=1;j<=noelements;j++) {
8625
if(inside[j] == 2) {
8626
elemtype = data->elementtypes[j];
8627
for(i=0;i<elemtype%100;i++)
8628
newtopo[j][i] = topomap[data->topology[j][i]];
8629
}
8630
}
8631
}
8632
8633
8634
/* Put the pointers to the enlarged data set and destroy the old data */
8635
oldx = data->x;
8636
oldy = data->y;
8637
oldtopo = data->topology;
8638
8639
data->noelements = noelements;
8640
data->noknots = noknots;
8641
data->x = newx;
8642
data->y = newy;
8643
data->z = newz;
8644
8645
free_Ivector(data->elementtypes,1,oldnoelements);
8646
data->elementtypes = newelementtypes;
8647
8648
free_Ivector(data->material,1,oldnoelements);
8649
data->material = newmaterial;
8650
data->topology = newtopo;
8651
8652
8653
/* In case one wants to fit the mesh inside the original mesh
8654
the mesh nodes may be put to new positions using an appropriate filter. */
8655
8656
8657
/* For higher order elements remove the middlenodes from the list of cornernodes */
8658
if(maxelemtype%100 > 4) {
8659
if(info) printf("Marking the higher order nodes\n");
8660
8661
nonlin = Ivector(1,noknots);
8662
for(i=1;i<=noknots;i++) nonlin[i] = FALSE;
8663
8664
for(j=1;j<=noelements;j++) {
8665
elemtype = data->elementtypes[j];
8666
for(i=elemtype/100;i<elemtype%100;i++) {
8667
k = data->topology[j][i];
8668
nonlin[k] = TRUE;
8669
}
8670
}
8671
}
8672
8673
8674
if(maxfilters) {
8675
int method,iter;
8676
int ind1,ind2,ind3,*fixedx=NULL,*fixedy=NULL;
8677
Real *aidx=NULL,*aidy=NULL,*weights=NULL;
8678
Real maxerror=0.0,minds,dx2,dy2,ds2,fii;
8679
8680
/* There are three methods how to put the weight in the filter,
8681
1) 1/s, 2) fii/s, 3) sin(fii)/s, the second option seems to be best. */
8682
method = 2;
8683
8684
if(info) printf("Filtering the mesh to meet the original geometry\n");
8685
8686
fixedx = Ivector(1,noknots);
8687
fixedy = Ivector(1,noknots);
8688
weights = Rvector(1,noknots);
8689
aidx = Rvector(1,noknots);
8690
aidy = Rvector(1,noknots);
8691
8692
/* Set all the fixed boundaries */
8693
for(i=1;i<=noknots;i++) fixedx[i] = fixedy[i] = 0;
8694
8695
/* First, make all other materials except the ones with BL to be fixed */
8696
if(checkmaterials) {
8697
for(j=1;j<=noelements;j++) {
8698
8699
elemtype = data->elementtypes[j];
8700
dolayer = FALSE;
8701
for(k=0;k<nolayers;k++)
8702
if(data->material[j] == layerparents[k]) dolayer = TRUE;
8703
8704
for(i=0;i<elemtype/100;i++) {
8705
ind1 = data->topology[j][i];
8706
if(dolayer && fixedx[ind1]%2 == 0)
8707
fixedx[ind1] += 1;
8708
if(!dolayer && fixedx[ind1] < 2)
8709
fixedx[ind1] += 2;
8710
}
8711
}
8712
for(i=1;i<=noknots;i++) {
8713
if(fixedx[i] == 2)
8714
fixedy[i] = 2;
8715
else
8716
fixedx[i] = 0;
8717
}
8718
}
8719
8720
/* Then set all BC:s fixed except the tangential ones */
8721
for(j=0;j<MAXBOUNDARIES;j++) {
8722
if(!bound[j].created) continue;
8723
8724
for(i=1;i<=bound[j].nosides;i++) {
8725
8726
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8727
data,ind,&sideelemtype);
8728
8729
dx = fabs(newx[ind[0]] - newx[ind[1]]);
8730
dy = fabs(newy[ind[0]] - newy[ind[1]]);
8731
if(dx > rectfactor * dy) {
8732
for(l=0;l<sideelemtype%100;l++) {
8733
fixedy[ind[l]] = TRUE;
8734
}
8735
}
8736
else if(dy > rectfactor * dx) {
8737
for(l=0;l<sideelemtype%100;l++) {
8738
fixedx[ind[l]] = TRUE;
8739
}
8740
}
8741
else {
8742
for(l=0;l<sideelemtype%100;l++) {
8743
fixedy[ind[l]] = TRUE;
8744
fixedx[ind[l]] = TRUE;
8745
}
8746
}
8747
}
8748
}
8749
8750
8751
/* Then set possibly all remaining active boundaries to be fixed */
8752
for(j=0;j<MAXBOUNDARIES;j++) {
8753
if(!bound[j].created) continue;
8754
8755
for(i=1;i<=bound[j].nosides;i++) {
8756
8757
dolayer = FALSE;
8758
parent = bound[j].parent[i];
8759
parent2 = bound[j].parent2[i];
8760
use2 = FALSE;
8761
8762
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8763
data,ind,&sideelemtype);
8764
8765
for(k=0;k<nolayers;k++) {
8766
if(bound[j].types[i] == layerbounds[k]) {
8767
if(checkmaterials) {
8768
if(layerparents[k] < 0) continue;
8769
8770
if(data->material[parent] == layerparents[k]) {
8771
dolayer = k + 1;
8772
}
8773
else if(parent2) {
8774
l = parent;
8775
parent = parent2;
8776
parent2 = l;
8777
if(data->material[parent] == layerparents[k]) {
8778
use2 = TRUE;
8779
dolayer = k + 1;
8780
}
8781
}
8782
}
8783
else dolayer = k + 1;
8784
}
8785
}
8786
8787
if(dolayer) {
8788
for(l=0;l<sideelemtype%100;l++) {
8789
fixedy[ind[l]] = TRUE;
8790
fixedx[ind[l]] = TRUE;
8791
}
8792
}
8793
}
8794
}
8795
8796
/* Finally loose the problematic triple nodes */
8797
for(j=1;j<=endbcs;j++) {
8798
k = endnodes[j];
8799
if(k) {
8800
fixedx[k] = FALSE;
8801
fixedy[k] = FALSE;
8802
}
8803
8804
/* for second order elements */
8805
k = endnodes2[j];
8806
if(k) {
8807
fixedx[k] = FALSE;
8808
fixedy[k] = FALSE;
8809
}
8810
}
8811
8812
8813
j = 0;
8814
for(i=1;i<=noknots;i++) if(fixedx[i]) j += 1;
8815
if(info) printf("Number of fixed nodes in x-direction is %d\n",j);
8816
8817
j = 0;
8818
for(i=1;i<=noknots;i++) if(fixedy[i]) j += 1;
8819
if(info) printf("Number of fixed nodes in y-direction is %d\n",j);
8820
8821
for(j=1;j<=noknots;j++) {
8822
8823
if(fixedx[j]) {
8824
if(j <= oldnoknots)
8825
newx[j] = aidx[j] = oldx[j];
8826
else
8827
newx[j] = aidx[j] = oldx[herit[j]];
8828
}
8829
if(fixedy[j]) {
8830
if(j <= oldnoknots)
8831
newy[j] = aidy[j] = oldy[j];
8832
else
8833
newy[j] = aidy[j] = oldy[herit[j]];
8834
}
8835
}
8836
8837
8838
for(iter=1;iter<=maxfilters;iter++) {
8839
maxerror = 0.0;
8840
minds = 1.0e10;
8841
8842
for(j=1;j<=noknots;j++) {
8843
8844
weights[j] = 0.0;
8845
8846
if(!fixedx[j]) {
8847
aidx[j] = newx[j];
8848
newx[j] = 0.0;
8849
}
8850
if(!fixedy[j]) {
8851
aidy[j] = newy[j];
8852
newy[j] = 0.0;
8853
}
8854
}
8855
8856
for(j=1;j<=noelements;j++) {
8857
elemtype = data->elementtypes[j];
8858
nonodes = elemtype / 100;
8859
8860
for(i=0;i<nonodes;i++) {
8861
8862
i2 = (i+1)%nonodes;
8863
i3 = (i+2)%nonodes;
8864
8865
ind1 = data->topology[j][i];
8866
ind2 = data->topology[j][i2];
8867
ind3 = data->topology[j][i3];
8868
8869
if(j<=oldnoelements) {
8870
dx = oldx[oldtopo[j][i2]] - oldx[oldtopo[j][i]];
8871
dy = oldy[oldtopo[j][i2]] - oldy[oldtopo[j][i]];
8872
ds = sqrt(dx*dx+dy*dy);
8873
}
8874
else {
8875
ds = fabs(elemwidth[j-oldnoelements]);
8876
}
8877
if(ds < minds) minds = ds;
8878
8879
8880
if(j<=oldnoelements) {
8881
dx2 = oldx[oldtopo[j][i2]] - oldx[oldtopo[j][i3]];
8882
dy2 = oldy[oldtopo[j][i2]] - oldy[oldtopo[j][i3]];
8883
ds2 = sqrt(dx2*dx2+dy2*dy2);
8884
}
8885
else {
8886
ds2 = fabs(elemwidth[j-oldnoelements]);
8887
}
8888
8889
if(j <= oldnoelements && ds * ds2 < 1.0e-50) {
8890
printf("problem elem %d and nodes %d (%d %d)\n",j,i2,i,i3);
8891
printf("dist ds=%.3e ds2=%.3e\n",ds,ds2);
8892
printf("coord: %.3e %.3e\n",oldx[oldtopo[j][i2]], oldy[oldtopo[j][i2]]);
8893
continue;
8894
}
8895
8896
if(abs(method) == 2 && j<=oldnoelements) {
8897
fii = acos((dx*dx2+dy*dy2)/(ds*ds2)) / (FM_PI/2.0);
8898
}
8899
else if(abs(method) == 3 && j<=oldnoelements) {
8900
fii = acos((dx*dx2+dy*dy2)/(ds*ds2));
8901
fii = sin(fii);
8902
}
8903
else {
8904
fii = 1.0;
8905
}
8906
8907
8908
/* Eliminate the very difficult triple nodes */
8909
dolayer = FALSE;
8910
for(k=1;k<=endbcs;k++)
8911
if(ind2 == endnodes[k]) dolayer = k;
8912
8913
if(dolayer) {
8914
for(k=1;k<=2;k++) {
8915
if(endneighbours[2*(dolayer-1)+k] == ind1) {
8916
weights[ind2] += fii / ds;
8917
if(!fixedx[ind2]) newx[ind2] += aidx[ind1] * fii / ds;
8918
if(!fixedy[ind2]) newy[ind2] += aidy[ind1] * fii / ds;
8919
}
8920
}
8921
for(k=1;k<=2;k++) {
8922
if(endneighbours[2*(dolayer-1)+k] == ind3) {
8923
weights[ind2] += fii / ds2;
8924
if(!fixedx[ind2]) newx[ind2] += aidx[ind3] * fii / ds2;
8925
if(!fixedy[ind2]) newy[ind2] += aidy[ind3] * fii / ds2;
8926
}
8927
}
8928
}
8929
else {
8930
if(ind2 <= oldnoknots || herit[ind1] == herit[ind2]) {
8931
weights[ind2] += fii / ds;
8932
if(!fixedx[ind2]) newx[ind2] += aidx[ind1] * fii / ds;
8933
if(!fixedy[ind2]) newy[ind2] += aidy[ind1] * fii / ds;
8934
}
8935
8936
if(ind2 <= oldnoknots || herit[ind3] == herit[ind2]) {
8937
weights[ind2] += fii / ds2;
8938
if(!fixedx[ind2]) newx[ind2] += aidx[ind3] * fii / ds2;
8939
if(!fixedy[ind2]) newy[ind2] += aidy[ind3] * fii / ds2;
8940
}
8941
}
8942
}
8943
}
8944
8945
if(maxelemtype%100 > 4) {
8946
for(j=1;j<=noknots;j++) {
8947
if(nonlin[j]) continue;
8948
8949
if(weights[j] > 1.0e-50) {
8950
if(!fixedx[j]) newx[j] /= weights[j];
8951
if(!fixedy[j]) newy[j] /= weights[j];
8952
}
8953
else if(iter==1) {
8954
printf("no weight for index %d\n",j);
8955
}
8956
8957
dx = newx[j] - aidx[j];
8958
dy = newy[j] - aidy[j];
8959
8960
ds = dx*dx + dy*dy;
8961
if(ds > maxerror) maxerror = ds;
8962
}
8963
}
8964
else {
8965
for(j=1;j<=noknots;j++) {
8966
if(!fixedx[j]) newx[j] /= weights[j];
8967
if(!fixedy[j]) newy[j] /= weights[j];
8968
8969
dx = newx[j]-aidx[j];
8970
dy = newy[j]-aidy[j];
8971
8972
ds = dx*dx + dy*dy;
8973
if(ds > maxerror) maxerror = ds;
8974
}
8975
}
8976
8977
maxerror = sqrt(maxerror) / minds;
8978
if(maxerror < layereps) break;
8979
}
8980
8981
if(info) {
8982
printf("Filtered the new node coordinates %d times with final error %.3e.\n",
8983
iter-1,maxerror);
8984
}
8985
8986
/* In higher order elements map the middle nodes so that they lie in between
8987
the corner nodes */
8988
8989
8990
if(maxelemtype%100 > 4) {
8991
for(j=1;j<=noelements;j++) {
8992
elemtype = data->elementtypes[j];
8993
if(elemtype%100 <= elemtype/100) continue;
8994
8995
if(elemtype == 306) {
8996
for(k=0;k<3;k++) {
8997
if(!fixedx[newtopo[j][k+3]]) {
8998
newx[newtopo[j][k+3]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%3]]);
8999
}
9000
if(!fixedy[newtopo[j][k+3]]) {
9001
newy[newtopo[j][k+3]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%3]]);
9002
}
9003
}
9004
}
9005
9006
else if(elemtype == 408 || elemtype == 409) {
9007
9008
if(elemtype == 409) {
9009
newx[newtopo[j][8]] = 0.0;
9010
newy[newtopo[j][8]] = 0.0;
9011
}
9012
9013
for(k=0;k<4;k++) {
9014
if(!fixedx[newtopo[j][k+4]]) {
9015
newx[newtopo[j][k+4]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%4]]);
9016
}
9017
if(!fixedy[newtopo[j][k+4]]) {
9018
newy[newtopo[j][k+4]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%4]]);
9019
}
9020
if(elemtype == 409) {
9021
newx[newtopo[j][8]] += 0.25 * newx[newtopo[j][k]];
9022
newy[newtopo[j][8]] += 0.25 * newy[newtopo[j][k]];
9023
}
9024
}
9025
}
9026
else {
9027
printf("Unknown elementtype %d\n",elemtype);
9028
}
9029
}
9030
}
9031
9032
free_Ivector(fixedx,1,noknots);
9033
free_Ivector(fixedy,1,noknots);
9034
9035
free_Rvector(aidx,1,noknots);
9036
free_Rvector(aidy,1,noknots);
9037
free_Rvector(weights,1,noknots);
9038
}
9039
9040
if(bound[newbc].nosides > 0)
9041
bound[newbc].created = TRUE;
9042
9043
9044
/* In higher order elements map the middle nodes so that they lie in between
9045
the corner nodes. Elemtypes must be 408 or 409 since they are created in this
9046
subroutine */
9047
9048
if(!maxfilters && maxelemtype%100 > 4) {
9049
if(info) printf("Making the higher order nodes to lie in between\n");
9050
9051
for(j=oldnoelements+1;j<=noelements;j++) {
9052
9053
elemtype = data->elementtypes[j];
9054
if(elemtype%100 <= elemtype/100) continue;
9055
9056
if(elemtype == 408 || elemtype == 409) {
9057
9058
if(elemtype == 409) {
9059
newx[newtopo[j][8]] = 0.0;
9060
newy[newtopo[j][8]] = 0.0;
9061
}
9062
9063
for(k=0;k<4;k++) {
9064
newx[newtopo[j][k+4]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%4]]);
9065
newy[newtopo[j][k+4]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%4]]);
9066
9067
if(elemtype == 409) {
9068
newx[newtopo[j][8]] += 0.25 * newx[newtopo[j][k]];
9069
newy[newtopo[j][8]] += 0.25 * newy[newtopo[j][k]];
9070
}
9071
}
9072
}
9073
}
9074
}
9075
9076
9077
#if 0
9078
ReorderElements(data,bound,FALSE,corder,info);
9079
#endif
9080
9081
free_Imatrix(oldtopo,1,oldnoelements,0,oldmaxnodes-1);
9082
free_Ivector(layernode,1,oldnoknots);
9083
free_Rvector(oldx,1,oldnoknots);
9084
free_Rvector(oldy,1,oldnoknots);
9085
9086
if(info) printf("Boundary layers created successfully.\n");
9087
9088
if(checkmaterials && !second) {
9089
for(k=0;k<nolayers;k++) {
9090
if(layerparents[k] < 0) second = TRUE;
9091
layerparents[k] = -layerparents[k];
9092
}
9093
if(second) {
9094
if(info) printf("\nPerforming boundary layer generation again for negative materials\n");
9095
goto omstart;
9096
}
9097
}
9098
9099
return(0);
9100
}
9101
9102
9103
9104
9105
9106
int CreateBoundaryLayerDivide(struct FemType *data,struct BoundaryType *bound,
9107
int nolayers, int *layerbounds, int *layernumber,
9108
Real *layerratios, Real *layerthickness, int *layerparents,
9109
int info)
9110
/* Create Boundary layers that may be used to solve accurately fluid
9111
flow problems and similar equations. In this subroutine the boundary layer
9112
is created by dividing the elements close to boundary. */
9113
{
9114
int i,j,k,l,dim,maxbc,maxelemtype,dolayer,parent,nlayer,sideelemtype,elemind,side;
9115
int noelements,noknots,oldnoknots,oldnoelements,oldmaxnodes,nonewnodes,nonewelements;
9116
int maxcon,elemsides,elemdone,midpoints,order,bcnodes,elemhits,elemtype,goforit;
9117
int ind[MAXNODESD2],baseind[2],topnode[2],basenode[2];
9118
int *layernode=NULL,*newelementtypes=NULL,**newtopo=NULL,**oldtopo=NULL;
9119
int *newmaterial=NULL,**edgepairs=NULL,*sharednode=NULL;
9120
Real dx[2],dy[2],x0[2],y0[2];
9121
Real *newx=NULL,*newy=NULL,*newz=NULL,*oldx=NULL,*oldy=NULL,*oldz=NULL;
9122
Real slayer,qlayer,ratio,q;
9123
9124
9125
dim = data->dim;
9126
maxelemtype = GetMaxElementType(data);
9127
9128
if(maxelemtype > 409) {
9129
printf("Subroutine implemented only up to 2nd degree!\n");
9130
return(2);
9131
}
9132
9133
if(info) printf("Largest elementtype is %d\n",maxelemtype);
9134
9135
9136
oldnoelements = noelements = data->noelements;
9137
oldnoknots = noknots = data->noknots;
9138
oldmaxnodes = data->maxnodes;
9139
9140
layernode = Ivector(1,oldnoknots);
9141
for(i=1;i<=oldnoknots;i++)
9142
layernode[i] = 0;
9143
9144
sharednode = Ivector(1,oldnoknots);
9145
for(i=1;i<=oldnoknots;i++)
9146
sharednode[i] = 0;
9147
9148
9149
/* Go through all the boundaries with boundary layer definitions and compute
9150
the number of nodes at the surface. */
9151
9152
maxbc = 0;
9153
qlayer = 0.0;
9154
slayer = 0.0;
9155
nlayer = 0;
9156
9157
/* Go through the layers and check which ones are active */
9158
for(j=0;j<MAXBOUNDARIES;j++) {
9159
if(!bound[j].created) continue;
9160
9161
for(i=1;i<=bound[j].nosides;i++) {
9162
dolayer = FALSE;
9163
parent = bound[j].parent[i];
9164
if(bound[j].types[i] > maxbc) maxbc = bound[j].types[i];
9165
9166
for(k=0;k<nolayers;k++) {
9167
if(bound[j].types[i] == layerbounds[k]) {
9168
nlayer = layernumber[k];
9169
slayer = layerthickness[k];
9170
qlayer = layerratios[k];
9171
dolayer = TRUE;
9172
}
9173
}
9174
if(!dolayer) continue;
9175
9176
/* We have found an active boundary layer */
9177
GetElementSide(parent,bound[j].side[i],bound[j].normal[i],
9178
data,ind,&sideelemtype);
9179
9180
midpoints = FALSE;
9181
if(sideelemtype == 202) {
9182
order = 1;
9183
}
9184
else if(sideelemtype == 203) {
9185
order = 2;
9186
if(maxelemtype > 408) midpoints = TRUE;
9187
}
9188
9189
for(l=0;l<sideelemtype%100;l++)
9190
layernode[ind[l]] += 1;
9191
}
9192
}
9193
9194
if(slayer > 1.0 || slayer < 1.0e-20)
9195
slayer = 1.0;
9196
9197
bcnodes = 0;
9198
maxcon = 0;
9199
for(i=1;i<=data->noknots;i++) {
9200
if(layernode[i]) bcnodes++;
9201
maxcon = MAX(maxcon, layernode[i]);
9202
}
9203
9204
if(info) printf("Found %d new nodes in the boundary layers!\n",bcnodes);
9205
if(!bcnodes) return(0);
9206
if(info) printf("There are %d connections at maximum\n",maxcon);
9207
9208
/* there will be more nodes if the original mesh consists of triangles */
9209
if(maxelemtype <= 303)
9210
data->maxnodes = 4;
9211
else if(maxelemtype == 306)
9212
data->maxnodes = 8;
9213
9214
/* Compute the number of new elements */
9215
nonewelements = 0;
9216
for(j=1;j<=data->noelements;j++) {
9217
elemhits = 0;
9218
elemtype = data->elementtypes[j];
9219
for(i=0;i<elemtype%100;i++) {
9220
k = data->topology[j][i];
9221
if( layernode[k]) {
9222
sharednode[k] += 1;
9223
elemhits++;
9224
}
9225
}
9226
if(elemhits) {
9227
nonewelements += nlayer ;
9228
if(elemhits != 2) nonewelements += nlayer + 1;
9229
}
9230
}
9231
printf("There will %d new elements\n",nonewelements);
9232
9233
/* This is a conservative estimate */
9234
nonewnodes = 2*nonewelements;
9235
9236
edgepairs = Imatrix(1,nonewnodes,1,3);
9237
for(j=1;j<=nonewnodes;j++)
9238
edgepairs[j][1] = edgepairs[j][2] = edgepairs[j][3] = 0;
9239
9240
9241
/* The size of new mesh */
9242
oldnoelements = data->noelements;
9243
oldnoknots = data->noknots;
9244
oldtopo = data->topology;
9245
oldx = data->x;
9246
oldy = data->y;
9247
oldz = data->z;
9248
9249
noknots = oldnoknots + nonewnodes;
9250
noelements = oldnoelements + nonewelements;
9251
9252
if(info) {
9253
printf("Creating additional %d elements and %d nodes.\n",nonewelements,nonewnodes);
9254
printf("Boundary layer mesh has at maximum %d elements and %d nodes.\n",noelements,noknots);
9255
}
9256
9257
/* Allocate more space for the enlarged data set */
9258
newtopo = Imatrix(1,noelements,0,data->maxnodes-1);
9259
newmaterial = Ivector(1,noelements);
9260
newelementtypes = Ivector(1,noelements);
9261
newx = Rvector(1,noknots);
9262
newy = Rvector(1,noknots);
9263
newz = Rvector(1,noknots);
9264
9265
/* Set the old topology */
9266
for(j=1;j<=data->noelements;j++) {
9267
newmaterial[j] = data->material[j];
9268
newelementtypes[j] = data->elementtypes[j];
9269
for(i=0;i<data->elementtypes[j]%100;i++)
9270
newtopo[j][i] = data->topology[j][i];
9271
}
9272
9273
/* Set the old nodes */
9274
for(i=1;i<=data->noknots;i++) {
9275
newx[i] = data->x[i];
9276
newy[i] = data->y[i];
9277
newz[i] = data->z[i];
9278
}
9279
9280
noelements = data->noelements;
9281
elemind = noelements;
9282
noknots = data->noknots;
9283
9284
/* Go through elements and make the new elements and nodes */
9285
for(j=1;j<=data->noelements;j++) {
9286
elemhits = 0;
9287
elemtype = data->elementtypes[j];
9288
elemsides = elemtype % 100;
9289
for(i=0;i<elemsides;i++)
9290
if( layernode[ data->topology[j][i] ]) elemhits++;
9291
if(!elemhits) continue;
9292
9293
if(elemtype == 404) {
9294
elemdone = FALSE;
9295
9296
for(side=0;side<elemsides;side++) {
9297
9298
goforit = FALSE;
9299
if(elemhits == 2 || elemhits == 3)
9300
if(layernode[oldtopo[j][side]] && layernode[oldtopo[j][(side+1)%elemsides]]) goforit = TRUE;
9301
if(elemhits == 1)
9302
if(layernode[oldtopo[j][side]]) goforit = TRUE;
9303
if(!goforit) continue;
9304
9305
/* Treat the special case of three hits
9306
In case of corners find the single node that is not on the boundary */
9307
if(elemhits == 3) {
9308
for(k=0;k<4;k++)
9309
if(!layernode[oldtopo[j][k]]) break;
9310
if(0) printf("Special node %d in corner %d\n",oldtopo[j][k],k);
9311
9312
basenode[0] = oldtopo[j][side];
9313
basenode[1] = oldtopo[j][(side+1)%elemsides];
9314
topnode[0] = oldtopo[j][k];
9315
topnode[1] = oldtopo[j][k];
9316
}
9317
else if(elemhits == 2) {
9318
basenode[0] = oldtopo[j][side];
9319
basenode[1] = oldtopo[j][(side+1)%elemsides];
9320
topnode[0] = oldtopo[j][(side+3)%elemsides];
9321
topnode[1] = oldtopo[j][(side+2)%elemsides];
9322
}
9323
else if(elemhits == 1) {
9324
basenode[0] = oldtopo[j][side];
9325
basenode[1] = basenode[0];
9326
topnode[0] = oldtopo[j][(side+3)%elemsides];
9327
topnode[1] = oldtopo[j][(side+1)%elemsides];
9328
}
9329
9330
for(k=0;k<=1;k++) {
9331
for(i=1;i<=nonewnodes;i++) {
9332
if(!edgepairs[i][1]) break;
9333
if(basenode[k] == edgepairs[i][1] && topnode[k] == edgepairs[i][2]) break;
9334
}
9335
if(!edgepairs[i][1]) {
9336
edgepairs[i][1] = basenode[k];
9337
edgepairs[i][2] = topnode[k];
9338
baseind[k] = noknots;
9339
edgepairs[i][3] = baseind[k];
9340
noknots += nlayer;
9341
}
9342
else {
9343
if(0) printf("Using existing nodes\n");
9344
baseind[k] = edgepairs[i][3];
9345
}
9346
x0[k] = oldx[basenode[k]];
9347
y0[k] = oldy[basenode[k]];
9348
dx[k] = oldx[topnode[k]] - x0[k];
9349
dy[k] = oldy[topnode[k]] - y0[k];
9350
9351
for(i=1;i<=nlayer;i++) {
9352
if(nlayer <= 1 || fabs(qlayer-1.0) < 0.001) {
9353
q = (1.0*i) / (nlayer+1);
9354
}
9355
else {
9356
ratio = pow(qlayer,1.0/nlayer);
9357
q = (1.- pow(ratio,1.0*i)) / (1.- pow(ratio,1.0+nlayer));
9358
}
9359
q *= slayer;
9360
newx[baseind[k]+i] = x0[k] + q * dx[k];
9361
newy[baseind[k]+i] = y0[k] + q * dy[k];
9362
}
9363
}
9364
9365
/* 0:th element */
9366
if(elemhits == 1) {
9367
newelementtypes[j] = 303;
9368
newtopo[j][0] = basenode[0];
9369
newtopo[j][1] = baseind[1] + 1;
9370
newtopo[j][2] = baseind[0] + 1;
9371
}
9372
else if(elemhits == 3 && elemdone) {
9373
elemind++;
9374
newelementtypes[elemind] = 404;
9375
newmaterial[elemind] = newmaterial[j];
9376
newtopo[elemind][side] = basenode[0];
9377
newtopo[elemind][(side+1)%elemsides] = basenode[1];
9378
newtopo[elemind][(side+2)%elemsides] = baseind[1] + 1;
9379
newtopo[elemind][(side+3)%elemsides] = baseind[0] + 1;
9380
}
9381
else {
9382
newtopo[j][(side+2)%elemsides] = baseind[1] + 1;
9383
newtopo[j][(side+3)%elemsides] = baseind[0] + 1;
9384
}
9385
9386
for(i=1;i<nlayer;i++) {
9387
elemind++;
9388
newelementtypes[elemind] = 404;
9389
newmaterial[elemind] = newmaterial[j];
9390
newtopo[elemind][0] = baseind[0] + i;
9391
newtopo[elemind][1] = baseind[1] + i;
9392
newtopo[elemind][2] = baseind[1] + i+1;
9393
newtopo[elemind][3] = baseind[0] + i+1;
9394
}
9395
9396
/* n:th element */
9397
if(elemhits == 3) {
9398
elemind++;
9399
newelementtypes[elemind] = 303;
9400
newmaterial[elemind] = newmaterial[j];
9401
newtopo[elemind][0] = baseind[0] + nlayer;
9402
newtopo[elemind][1] = baseind[1] + nlayer;
9403
newtopo[elemind][2] = topnode[0];
9404
}
9405
else if(elemhits == 2 || elemhits == 1) {
9406
elemind++;
9407
newelementtypes[elemind] = 404;
9408
newmaterial[elemind] = newmaterial[j];
9409
newtopo[elemind][0] = baseind[0] + nlayer;
9410
newtopo[elemind][1] = baseind[1] + nlayer;
9411
newtopo[elemind][2] = topnode[1];
9412
newtopo[elemind][3] = topnode[0];
9413
}
9414
/* n+1:th element */
9415
if(elemhits == 1) {
9416
elemind++;
9417
newelementtypes[elemind] = 303;
9418
newmaterial[elemind] = newmaterial[j];
9419
newtopo[elemind][0] = topnode[1];
9420
newtopo[elemind][1] = oldtopo[j][(side+2)%elemsides];
9421
newtopo[elemind][2] = topnode[0];
9422
}
9423
9424
elemdone = TRUE;
9425
}
9426
if(!elemdone)
9427
printf("cannot handle quadrilaterals with %d hits\n",elemhits);
9428
}
9429
9430
9431
else if(elemtype == 303) {
9432
elemdone = FALSE;
9433
9434
for(side=0;side<elemsides;side++) {
9435
9436
goforit = FALSE;
9437
if(elemhits == 2) {
9438
if(layernode[oldtopo[j][side]] && layernode[oldtopo[j][(side+1)%elemsides]]) goforit = TRUE;
9439
}
9440
else if(elemhits == 1) {
9441
if(layernode[oldtopo[j][side]]) goforit = TRUE;
9442
}
9443
else if(elemhits == 3) {
9444
if(sharednode[oldtopo[j][side]] == 1) goforit = TRUE;
9445
9446
printf("The boundary layer creation for certain corner triangles is omitted\n");
9447
goforit = FALSE;
9448
}
9449
if(!goforit) continue;
9450
9451
if(elemhits == 3) {
9452
if(1) printf("Special node %d in corner %d\n",oldtopo[j][side],side);
9453
basenode[0] = oldtopo[j][side];
9454
basenode[1] = basenode[0];
9455
topnode[0] = oldtopo[j][(side+2)%elemsides];
9456
topnode[1] = oldtopo[j][(side+1)%elemsides];
9457
}
9458
else if(elemhits == 2) {
9459
basenode[0] = oldtopo[j][side];
9460
basenode[1] = oldtopo[j][(side+1)%elemsides];
9461
topnode[0] = oldtopo[j][(side+2)%elemsides];
9462
topnode[1] = topnode[0];
9463
}
9464
else if(elemhits == 1) {
9465
basenode[0] = oldtopo[j][side];
9466
basenode[1] = basenode[0];
9467
topnode[0] = oldtopo[j][(side+2)%elemsides];
9468
topnode[1] = oldtopo[j][(side+1)%elemsides];
9469
}
9470
9471
for(k=0;k<=1;k++) {
9472
for(i=1;i<=nonewnodes;i++) {
9473
if(!edgepairs[i][1]) break;
9474
if(basenode[k] == edgepairs[i][1] && topnode[k] == edgepairs[i][2]) break;
9475
}
9476
if(!edgepairs[i][1]) {
9477
edgepairs[i][1] = basenode[k];
9478
edgepairs[i][2] = topnode[k];
9479
baseind[k] = noknots;
9480
edgepairs[i][3] = baseind[k];
9481
noknots += nlayer;
9482
}
9483
else {
9484
if(0) printf("Using existing nodes\n");
9485
baseind[k] = edgepairs[i][3];
9486
}
9487
9488
x0[k] = oldx[basenode[k]];
9489
y0[k] = oldy[basenode[k]];
9490
dx[k] = oldx[topnode[k]] - x0[k];
9491
dy[k] = oldy[topnode[k]] - y0[k];
9492
9493
for(i=1;i<=nlayer;i++) {
9494
if(nlayer <= 1 || fabs(qlayer-1.0) < 0.001) {
9495
q = (1.0*i) / (nlayer+1);
9496
}
9497
else {
9498
ratio = pow(qlayer,1.0/nlayer);
9499
q = (1.- pow(ratio,1.0*i)) / (1.- pow(ratio,1.0*nlayer));
9500
}
9501
q *= slayer;
9502
newx[baseind[k]+i] = x0[k] + q * dx[k];
9503
newy[baseind[k]+i] = y0[k] + q * dy[k];
9504
}
9505
}
9506
9507
/* 0:th element */
9508
if(elemhits == 1 || elemhits == 3) {
9509
newelementtypes[j] = 303;
9510
newtopo[j][0] = basenode[0];
9511
newtopo[j][1] = baseind[1] + 1;
9512
newtopo[j][2] = baseind[0] + 1;
9513
}
9514
else if(elemhits == 2) {
9515
newelementtypes[j] = 404;
9516
newtopo[j][side] = basenode[0];
9517
newtopo[j][(side+1)%4] = basenode[1];
9518
newtopo[j][(side+2)%4] = baseind[1] + 1;
9519
newtopo[j][(side+3)%4] = baseind[0] + 1;
9520
}
9521
9522
for(i=1;i<nlayer;i++) {
9523
elemind++;
9524
newelementtypes[elemind] = 404;
9525
newmaterial[elemind] = newmaterial[j];
9526
newtopo[elemind][0] = baseind[0] + i;
9527
newtopo[elemind][1] = baseind[1] + i;
9528
newtopo[elemind][2] = baseind[1] + i+1;
9529
newtopo[elemind][3] = baseind[0] + i+1;
9530
}
9531
9532
/* n:th element */
9533
if(elemhits == 1 || elemhits == 3) {
9534
elemind++;
9535
newelementtypes[elemind] = 404;
9536
newmaterial[elemind] = newmaterial[j];
9537
newtopo[elemind][0] = baseind[0] + nlayer;
9538
newtopo[elemind][1] = baseind[1] + nlayer;
9539
newtopo[elemind][2] = topnode[1];
9540
newtopo[elemind][3] = topnode[0];
9541
}
9542
else if(elemhits == 2) {
9543
elemind++;
9544
newelementtypes[elemind] = 303;
9545
newmaterial[elemind] = newmaterial[j];
9546
newtopo[elemind][0] = baseind[0] + nlayer;
9547
newtopo[elemind][1] = baseind[1] + nlayer;
9548
newtopo[elemind][2] = topnode[1];
9549
}
9550
elemdone = TRUE;
9551
}
9552
if(!elemdone)
9553
printf("cannot handle triangles with %d hits\n",elemhits);
9554
}
9555
9556
else {
9557
printf("Not implemented for element %d\n",elemtype);
9558
}
9559
}
9560
noelements = elemind;
9561
9562
data->x = newx;
9563
data->y = newy;
9564
data->topology = newtopo;
9565
data->material = newmaterial;
9566
data->elementtypes = newelementtypes;
9567
data->noknots = noknots;
9568
data->noelements = elemind;
9569
9570
printf("The created boundary layer mesh has at %d elements and %d nodes.\n",noelements,noknots);
9571
9572
return(0);
9573
}
9574
9575
9576
9577
int RotateTranslateScale(struct FemType *data,struct ElmergridType *eg,int info)
9578
{
9579
int i;
9580
Real x,y,z,xz,yz,yx,zx,zy,xy,cx,cy,cz;
9581
Real xmin, xmax, ymin, ymax, zmin, zmax;
9582
9583
if(eg->scale) {
9584
if(info) printf("Scaling mesh with vector [%.3lg %.3lg %.3lg]\n",
9585
eg->cscale[0],eg->cscale[1],eg->cscale[2]);
9586
for(i=1;i<=data->noknots;i++) {
9587
data->x[i] *= eg->cscale[0];
9588
data->y[i] *= eg->cscale[1];
9589
data->z[i] *= eg->cscale[2];
9590
}
9591
if(0) printf("Scaling of mesh finished.\n");
9592
}
9593
9594
if(eg->rotate) {
9595
if(info) printf("Rotating mesh with degrees [%.3lg %.3lg %.3lg]\n",
9596
eg->crotate[0],eg->crotate[1],eg->crotate[2]);
9597
cx = FM_PI * eg->crotate[0]/180.0;
9598
cy = FM_PI * eg->crotate[1]/180.0;
9599
cz = FM_PI * eg->crotate[2]/180.0;
9600
9601
for(i=1;i<=data->noknots;i++) {
9602
9603
x = data->x[i];
9604
y = data->y[i];
9605
z = data->z[i];
9606
9607
xz = x*cos(cz) + y*sin(cz);
9608
yz = -x*sin(cz) + y*cos(cz);
9609
9610
if( fabs(cx) > 1.0e-8 || fabs(cy) > 1.0e-8 ) {
9611
yx = yz*cos(cx) + z*sin(cx);
9612
zx = -yz*sin(cx) + z*cos(cx);
9613
9614
zy = zx*cos(cy) + xz*sin(cy);
9615
xy = -zx*sin(cy) + xz*cos(cy);
9616
9617
data->x[i] = xy;
9618
data->y[i] = yx;
9619
data->z[i] = zy;
9620
}
9621
else {
9622
data->x[i] = xz;
9623
data->y[i] = yz;
9624
}
9625
}
9626
if(0) printf("Rotation of mesh finished.\n");
9627
}
9628
9629
if(eg->translate) {
9630
if(info) printf("Translating the mesh with vector [%.3lg %.3lg %.3lg]\n",
9631
eg->ctranslate[0],eg->ctranslate[1],eg->ctranslate[2]);
9632
for(i=1;i<=data->noknots;i++) {
9633
data->x[i] += eg->ctranslate[0];
9634
data->y[i] += eg->ctranslate[1];
9635
data->z[i] += eg->ctranslate[2];
9636
}
9637
if(0) printf("Translation of mesh finished.\n");
9638
}
9639
9640
if(eg->center) {
9641
xmin = xmax = data->x[1];
9642
ymin = ymax = data->y[1];
9643
zmin = zmax = data->z[1];
9644
9645
for(i=1;i<=data->noknots;i++) {
9646
xmax = MAX( xmax, data->x[i] );
9647
xmin = MIN( xmin, data->x[i] );
9648
ymax = MAX( ymax, data->y[i] );
9649
ymin = MIN( ymin, data->y[i] );
9650
zmax = MAX( zmax, data->z[i] );
9651
zmin = MIN( zmin, data->z[i] );
9652
}
9653
cx = 0.5 * (xmin + xmax);
9654
cy = 0.5 * (ymin + ymax);
9655
cz = 0.5 * (zmin + zmax);
9656
9657
if(info) printf("Setting new center to %.3e %.3e %.3e\n",cx,cy,cz);
9658
9659
for(i=1;i<=data->noknots;i++) {
9660
data->x[i] -= cx;
9661
data->y[i] -= cy;
9662
data->z[i] -= cz;
9663
}
9664
}
9665
9666
return(0);
9667
}
9668
9669
9670
9671
int CreateNodalGraph(struct FemType *data,int full,int info)
9672
{
9673
int i,j,k,l,m,totcon,noelements, noknots,elemtype,nonodes,hit,ind,ind2;
9674
int maxcon,percon,edge;
9675
9676
printf("Creating a nodal graph of the finite element mesh\n");
9677
9678
if(data->nodalexists) {
9679
printf("The nodal graph already exists!\n");
9680
smallerror("Nodal graph not done");
9681
return(1);
9682
}
9683
9684
maxcon = 0;
9685
totcon = 0;
9686
percon = 0;
9687
noelements = data->noelements;
9688
noknots = data->noknots;
9689
9690
for(i=1;i<=noelements;i++) {
9691
elemtype = data->elementtypes[i];
9692
9693
/* This sets only the connections resulting from element edges */
9694
if(!full) {
9695
int inds[2];
9696
for(edge=0;;edge++) {
9697
if( !GetElementGraph(i,edge,data,&inds[0]) ) break;
9698
9699
ind = inds[0];
9700
ind2 = inds[1];
9701
9702
hit = FALSE;
9703
for(l=0;l<maxcon;l++) {
9704
if(data->nodalgraph[l][ind] == ind2) hit = TRUE;
9705
if(data->nodalgraph[l][ind] == 0) break;
9706
}
9707
if(!hit) {
9708
if(l >= maxcon) {
9709
data->nodalgraph[maxcon] = Ivector(1,noknots);
9710
for(m=1;m<=noknots;m++)
9711
data->nodalgraph[maxcon][m] = 0;
9712
maxcon++;
9713
}
9714
data->nodalgraph[l][ind] = ind2;
9715
totcon++;
9716
}
9717
9718
/* Make also so symmetric connection */
9719
for(l=0;l<maxcon;l++) {
9720
if(data->nodalgraph[l][ind2] == ind) hit = TRUE;
9721
if(data->nodalgraph[l][ind2] == 0) break;
9722
}
9723
if(!hit) {
9724
if(l >= maxcon) {
9725
data->nodalgraph[maxcon] = Ivector(1,noknots);
9726
for(m=1;m<=noknots;m++)
9727
data->nodalgraph[maxcon][m] = 0;
9728
maxcon++;
9729
}
9730
data->nodalgraph[l][ind2] = ind;
9731
totcon++;
9732
}
9733
}
9734
}
9735
9736
/* This sets all elemental connections */
9737
else {
9738
nonodes = data->elementtypes[i] % 100;
9739
for(j=0;j<nonodes;j++) {
9740
ind = data->topology[i][j];
9741
for(k=0;k<nonodes;k++) {
9742
ind2 = data->topology[i][k];
9743
if(ind == ind2) continue;
9744
9745
hit = FALSE;
9746
for(l=0;l<maxcon;l++) {
9747
if(data->nodalgraph[l][ind] == ind2) hit = TRUE;
9748
if(data->nodalgraph[l][ind] == 0) break;
9749
}
9750
if(!hit) {
9751
if(l >= maxcon) {
9752
data->nodalgraph[maxcon] = Ivector(1,noknots);
9753
for(m=1;m<=noknots;m++)
9754
data->nodalgraph[maxcon][m] = 0;
9755
maxcon++;
9756
}
9757
data->nodalgraph[l][ind] = ind2;
9758
totcon++;
9759
}
9760
}
9761
}
9762
}
9763
9764
}
9765
9766
/* This adds the periodic connections */
9767
if( data->periodicexist ) {
9768
for(ind=1;ind<=noknots;ind++) {
9769
ind2 = data->periodic[ind];
9770
if(ind == ind2) continue;
9771
9772
hit = FALSE;
9773
for(l=0;l<maxcon;l++) {
9774
if(data->nodalgraph[l][ind] == ind2) hit = TRUE;
9775
if(data->nodalgraph[l][ind] == 0) break;
9776
}
9777
if(!hit) {
9778
if(l >= maxcon) {
9779
data->nodalgraph[maxcon] = Ivector(1,noknots);
9780
for(m=1;m<=noknots;m++)
9781
data->nodalgraph[maxcon][m] = 0;
9782
maxcon++;
9783
}
9784
data->nodalgraph[l][ind] = ind2;
9785
totcon++;
9786
percon++;
9787
}
9788
}
9789
}
9790
9791
data->nodalmaxconnections = maxcon;
9792
data->nodalexists = TRUE;
9793
9794
if(info) {
9795
printf("There are at maximum %d connections in nodal graph.\n",maxcon);
9796
printf("There are at all in all %d connections in nodal graph.\n",totcon);
9797
if(percon) printf("There are %d periodic connections in nodal graph.\n",percon);
9798
}
9799
9800
return(0);
9801
}
9802
9803
9804
int DestroyNodalGraph(struct FemType *data,int info)
9805
{
9806
int i,maxcon, noknots;
9807
9808
if(!data->nodalexists) {
9809
printf("You tried to destroy a non-existing nodal graph\n");
9810
return(1);
9811
}
9812
9813
maxcon = data->nodalmaxconnections;
9814
noknots = data->noknots;
9815
9816
for(i=0;i<maxcon;i++)
9817
free_Ivector(data->nodalgraph[i],1,noknots);
9818
9819
data->nodalmaxconnections = 0;
9820
data->nodalexists = FALSE;
9821
9822
if(info) printf("The nodal graph was destroyed\n");
9823
return(0);
9824
}
9825
9826
9827
9828
int CreateInverseTopology(struct FemType *data,int info)
9829
{
9830
int i,j,k,l,m,noelements,noknots,elemtype,nonodes,ind;
9831
int *neededby,minneeded,maxneeded;
9832
int step,totcon;
9833
int *rows,*cols;
9834
struct CRSType *invtopo;
9835
9836
invtopo = &data->invtopo;
9837
if(invtopo->created) {
9838
if(0) printf("The inverse topology already exists!\n");
9839
return(0);
9840
}
9841
9842
printf("Creating an inverse topology of the finite element mesh\n");
9843
9844
noelements = data->noelements;
9845
noknots = data->noknots;
9846
9847
neededby = Ivector(1,noknots);
9848
totcon = 0;
9849
9850
for(step=1;step<=2;step++) {
9851
9852
for(i=1;i<=noknots;i++)
9853
neededby[i] = 0;
9854
9855
for(i=1;i<=noelements;i++) {
9856
elemtype = data->elementtypes[i];
9857
nonodes = data->elementtypes[i] % 100;
9858
9859
for(j=0;j<nonodes;j++) {
9860
ind = data->topology[i][j];
9861
9862
if( step == 1 ) {
9863
neededby[ind] += 1;
9864
totcon += 1;
9865
}
9866
else {
9867
k = rows[ind-1] + neededby[ind];
9868
cols[k] = i-1;
9869
neededby[ind] += 1;
9870
}
9871
}
9872
}
9873
9874
if( step == 1 ) {
9875
rows = Ivector( 0, noknots );
9876
rows[0] = 0;
9877
for(i=1;i<=noknots;i++)
9878
rows[i] = rows[i-1] + neededby[i];
9879
9880
cols = Ivector( 0, totcon-1 );
9881
for(i=0;i<totcon;i++)
9882
cols[i] = 0;
9883
9884
invtopo->cols = cols;
9885
invtopo->rows = rows;
9886
invtopo->colsize = totcon;
9887
invtopo->rowsize = noknots;
9888
invtopo->created = TRUE;
9889
}
9890
}
9891
9892
minneeded = maxneeded = neededby[1];
9893
for(i=1;i<=noknots;i++) {
9894
minneeded = MIN( minneeded, neededby[i]);
9895
maxneeded = MAX( maxneeded, neededby[i]);
9896
}
9897
9898
free_Ivector(neededby,1,noknots);
9899
9900
if(info) {
9901
printf("There are from %d to %d connections in the inverse topology.\n",minneeded,maxneeded);
9902
printf("Each node is in average in %.3f elements\n",1.0*totcon/noknots);
9903
}
9904
9905
return(0);
9906
}
9907
9908
9909
9910
int CreateDualGraph(struct FemType *data,int unconnected,int info)
9911
{
9912
int totcon,dcon,noelements,noknots,elemtype,nonodes,i,j,k,l,i2,m,ind,hit,ci,ci2;
9913
int dualmaxcon,invmaxcon,showgraph,freeelements,step,orphanelements,stat;
9914
int *elemconnect,*neededby;
9915
int *dualrow,*dualcol,dualsize,dualmaxelem,allocated;
9916
int *invrow,*invcol;
9917
struct CRSType *dualgraph;
9918
9919
if(info) printf("Creating a dual graph of the finite element mesh\n");
9920
9921
dualgraph = &data->dualgraph;
9922
if(dualgraph->created) {
9923
printf("The dual graph already exists!\n");
9924
return(1);
9925
}
9926
9927
CreateInverseTopology(data,info);
9928
9929
noelements = data->noelements;
9930
noknots = data->noknots;
9931
freeelements = noelements;
9932
orphanelements = 0;
9933
9934
/* If a dual graph only for the unconnected nodes is requested do that.
9935
Basically the connected nodes are omitted in the graph. */
9936
if( unconnected ) {
9937
if(info) printf("Removing connected nodes from the dual graph\n");
9938
if( data->nodeconnectexist ) {
9939
if(info) printf("Creating connected elements list from the connected nodes\n");
9940
SetConnectedElements(data,info);
9941
}
9942
if( data->elemconnectexist ) {
9943
elemconnect = data->elemconnect;
9944
freeelements -= data->elemconnectexist;
9945
}
9946
else {
9947
unconnected = FALSE;
9948
}
9949
if(info) printf("List of unconnected elements created\n");
9950
}
9951
9952
showgraph = FALSE;
9953
if(showgraph) printf("elemental graph ij pairs\n");
9954
9955
data->dualexists = TRUE;
9956
dualmaxcon = 0;
9957
dualmaxelem = 0;
9958
9959
invrow = data->invtopo.rows;
9960
invcol = data->invtopo.cols;
9961
9962
9963
/* This marker is used to identify the connections already accounted for */
9964
neededby = Ivector(1,freeelements);
9965
for(i=1;i<=freeelements;i++)
9966
neededby[i] = 0;
9967
9968
allocated = FALSE;
9969
omstart:
9970
9971
totcon = 0;
9972
9973
for(i=1;i<=noelements;i++) {
9974
if(showgraph) printf("%d :: ",i);
9975
9976
dcon = 0;
9977
elemtype = data->elementtypes[i];
9978
nonodes = data->elementtypes[i] % 100;
9979
9980
if( unconnected ) {
9981
ci = elemconnect[i];
9982
if( ci < 0 ) continue;
9983
}
9984
else {
9985
ci = i;
9986
}
9987
if(allocated) dualrow[ci-1] = totcon;
9988
9989
if(0) printf("i=%d %d\n",i,elemtype);
9990
9991
for(step=1;step<=2;step++) {
9992
for(j=0;j<nonodes;j++) {
9993
ind = data->topology[i][j];
9994
9995
if(0) printf("ind=%d\n",ind);
9996
9997
9998
for(k=invrow[ind-1];k<invrow[ind];k++) {
9999
i2 = invcol[k]+1;
10000
10001
if( i2 == i ) continue;
10002
10003
if( unconnected ) {
10004
ci2 = elemconnect[i2];
10005
if( ci2 < 0 ) continue;
10006
}
10007
else {
10008
ci2 = i2;
10009
}
10010
10011
/* In the first cycle mark the needed connections,
10012
and in the second cycle set the marker to zero for next round. */
10013
if( step == 1 ) {
10014
if( neededby[ci2] ) continue;
10015
neededby[ci2] = TRUE;
10016
10017
if(0) printf("ci ci2 = %d %d\n",ci,ci2);
10018
10019
/* If the dual graph has been allocated populate it */
10020
if(allocated) {
10021
dualcol[totcon] = ci2-1;
10022
}
10023
10024
dcon += 1;
10025
totcon += 1;
10026
if( dcon > dualmaxcon ) {
10027
dualmaxcon = dcon;
10028
dualmaxelem = i;
10029
}
10030
}
10031
else {
10032
neededby[ci2] = FALSE;
10033
}
10034
}
10035
}
10036
}
10037
if( dcon == 0 && allocated ) {
10038
orphanelements += 1;
10039
}
10040
}
10041
10042
if(allocated) {
10043
dualrow[dualsize] = totcon;
10044
}
10045
else {
10046
dualsize = freeelements;
10047
if(info) printf("Allocating for the dual graph for %d with %d connections\n",dualsize,totcon);
10048
dualrow = Ivector(0,dualsize);
10049
for(i=1;i<=dualsize;i++)
10050
dualrow[i] = 0;
10051
10052
dualcol = Ivector(0,totcon-1);
10053
for(i=0;i<totcon;i++)
10054
dualcol[i] = 0;
10055
10056
dualgraph->cols = dualcol;
10057
dualgraph->rows = dualrow;
10058
dualgraph->rowsize = dualsize;
10059
dualgraph->colsize = totcon;
10060
dualgraph->created = TRUE;
10061
10062
allocated = TRUE;
10063
10064
goto omstart;
10065
}
10066
10067
if( orphanelements && info ) {
10068
printf("There are %d elements in the dual mesh that are not connected!\n",orphanelements);
10069
if(unconnected) printf("The orphan elements are likely caused by the hybrid partitioning\n");
10070
}
10071
10072
10073
#if 0
10074
j = totcon; k = 0;
10075
for(i=1;i<=dualsize;i++){
10076
l = dualrow[i]-dualrow[i-1];
10077
if(l <= 0 ) printf("row(%d) = %d %d %d\n",i,l,dualrow[i],dualrow[i-1]);
10078
j = MIN(j,l);
10079
k = MAX(k,l);
10080
}
10081
printf("range dualrow: %d %d\n",j,k);
10082
10083
j = totcon; k = 0;
10084
for(i=0;i<totcon;i++) {
10085
j = MIN(j,dualcol[i]);
10086
k = MAX(k,dualcol[i]);
10087
}
10088
printf("range dualcol: %d %d\n",j,k);
10089
#endif
10090
10091
10092
if(info) {
10093
printf("There are at maximum %d connections in dual graph (in element %d).\n",dualmaxcon,dualmaxelem);
10094
printf("There are at all in all %d connections in dual graph.\n",totcon);
10095
printf("Average connection per active element in dual graph is %.3f\n",1.0*totcon/freeelements);
10096
}
10097
10098
free_Ivector( neededby,1,freeelements);
10099
10100
/* Inverse topology is created for partitioning only and then the direct
10101
topology is needed elsewhere as well. Do do not destroy it. */
10102
if(0) stat = DestroyInverseTopology(data,info);
10103
10104
return(0);
10105
}
10106
10107
10108
int DestroyCRSMatrix(struct CRSType *sp) {
10109
10110
if(sp->created) {
10111
if(0) printf("You tried to destroy a non-existing sparse matrix\n");
10112
return(1);
10113
}
10114
10115
free_Ivector( sp->rows, 0, sp->rowsize );
10116
free_Ivector( sp->cols, 0, sp->colsize-1);
10117
sp->rowsize = 0;
10118
sp->colsize = 0;
10119
sp->created = FALSE;
10120
10121
return(0);
10122
}
10123
10124
10125
int DestroyInverseTopology(struct FemType *data,int info)
10126
{
10127
int stat;
10128
stat = DestroyCRSMatrix( &data->invtopo );
10129
return(stat);
10130
}
10131
10132
int DestroyDualGraph(struct FemType *data,int info)
10133
{
10134
int stat;
10135
stat = DestroyCRSMatrix( &data->dualgraph );
10136
return(stat);
10137
}
10138
10139
10140
10141
10142
int MeshTypeStatistics(struct FemType *data,int info)
10143
{
10144
int i,elemtype,maxelemtype,minelemtype;
10145
int *elemtypes=NULL;
10146
10147
maxelemtype = minelemtype = data->elementtypes[1];
10148
10149
for(i=1;i<=data->noelements;i++) {
10150
elemtype = data->elementtypes[i];
10151
maxelemtype = MAX( maxelemtype, elemtype );
10152
minelemtype = MIN( minelemtype, elemtype );
10153
}
10154
10155
elemtypes = Ivector(minelemtype,maxelemtype);
10156
for(i=minelemtype;i<=maxelemtype;i++)
10157
elemtypes[i] = 0;
10158
10159
for(i=1;i<=data->noelements;i++) {
10160
elemtype = data->elementtypes[i];
10161
elemtypes[elemtype] += 1;
10162
}
10163
10164
if(info) {
10165
printf("Number of different elementtypes\n");
10166
for(i=minelemtype;i<=maxelemtype;i++)
10167
if(elemtypes[i]) printf("\t%d\t%d\n",i,elemtypes[i]);
10168
}
10169
10170
free_Ivector(elemtypes,minelemtype,maxelemtype);
10171
return(0);
10172
}
10173
10174
int BoundingBox(struct FemType *data,int nomesh,int nomeshes,int info)
10175
{
10176
int i;
10177
Real xmin, xmax, ymin, ymax, zmin, zmax, sidemax;
10178
10179
xmin = xmax = data->x[1];
10180
ymin = ymax = data->y[1];
10181
zmin = zmax = data->z[1];
10182
10183
for(i=1; i<=data->noknots; i++){
10184
xmax = MAX( xmax, data->x[i] );
10185
xmin = MIN( xmin, data->x[i] );
10186
ymax = MAX( ymax, data->y[i] );
10187
ymin = MIN( ymin, data->y[i] );
10188
zmax = MAX( zmax, data->z[i] );
10189
zmin = MIN( zmin, data->z[i] );
10190
}
10191
sidemax = MAX(xmax-xmin,ymax-ymin);
10192
sidemax = MAX(sidemax,zmax-zmin);
10193
10194
if(nomeshes > 1) {
10195
printf("Bounding box of all nodes in mesh[%d] of [%d] meshes:\n",nomesh,nomeshes);
10196
}
10197
else {
10198
printf("Bounding box of all nodes in mesh:\n");
10199
}
10200
10201
printf("X:[%lg,%lg] ",xmin,xmax);
10202
printf("Y:[%lg,%lg] ",ymin,ymax);
10203
printf("Z:[%lg,%lg]\n",zmin,zmax);
10204
10205
if(sidemax > 49.9) {
10206
printf("\nNotice: the longest bounding box side length of [%lg] is greater than 50.\n",sidemax);
10207
printf("ElmerGUI includes a library of material properties, defined in SI units. If using ElmerGUI, \n");
10208
printf("then the geometry is expected to have meters as length. Geometry that exceeds 50 meters \n");
10209
printf("in length or width or height may not be intended. Many Geometry generators assume \n");
10210
printf("millimeters as the basic unit of length. Scaling the geometry from millimeters to meters \n");
10211
printf("may be the desired action. For more help, search the Elmer users forum for posts \n");
10212
printf("about SI units, or for posts about Coordinate Scaling.\n");
10213
printf("Scaling can be accomplished in at least three ways, as follows:\n");
10214
printf(" 1. Define the original geometry in meters, not millimeters.\n");
10215
printf(" 2. Call ElmerGrid with -scale 0.001 0.001 0.001 as an option.\n");
10216
printf(" 3. Add Coordinate Scaling = 0.001 to the simulation section of the sif file.\n");
10217
printf("If using Elmer to analyze large geometry, such as a glacier, then ignore this notice.\n\n");
10218
}
10219
10220
return(0);
10221
}
10222
10223