Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
ElmerCSC
GitHub Repository: ElmerCSC/elmerfem
Path: blob/devel/ElmerGUI/Application/plugins/egmesh.cpp
5180 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[12+(side+1)%3];
457
ind[6] = elemind[9+side];
458
ind[7] = elemind[12+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 ModifyUnsupportedElements(struct FemType *data) {
6976
6977
int i,elementtype;
6978
int cnt718=0,cnt614=0,cnt409=0,cnt827=0;
6979
6980
for(i=1; i <= data->noelements; i++) {
6981
elementtype = data->elementtypes[i];
6982
if(elementtype == 718) {
6983
data->elementtypes[i] = 715;
6984
cnt718++;
6985
}
6986
else if(elementtype == 614) {
6987
data->elementtypes[i] = 613;
6988
cnt614++;
6989
}
6990
}
6991
6992
if(cnt718 || cnt614) {
6993
printf("WARNING: ElmerSolver does not currently support all elements in mesh, dropping center nodes!\n");
6994
for(i=1; i <= data->noelements; i++) {
6995
elementtype = data->elementtypes[i];
6996
if(elementtype == 409) {
6997
data->elementtypes[i] = 408;
6998
cnt409++;
6999
}
7000
else if(elementtype == 827) {
7001
data->elementtypes[i] = 820;
7002
cnt827++;
7003
}
7004
}
7005
if(cnt718) printf("Element type 718 not supported, dropping centernodes for %d elements\n",cnt718);
7006
if(cnt614) printf("Element type 614 not supported, dropping centernodes for %d elements\n",cnt614);
7007
if(cnt827) printf("Dropping centernodes in %d elements of type 827 as well!\n",cnt827);
7008
if(cnt409) printf("Dropping centernodes in %d elements of type 409 as well!\n",cnt409);
7009
}
7010
}
7011
7012
7013
7014
void ElementsToBoundaryConditions(struct FemType *data,
7015
struct BoundaryType *bound,int retainorphans,int info)
7016
{
7017
int i,j,k,l,sideelemtype,sideelemtype2,elemind,elemind2,sideelem,sameelem;
7018
int sideind[MAXNODESD1],sideind2[MAXNODESD1],elemsides,side,hit,same,minelemtype;
7019
int sidenodes,sidenodes2,maxelemtype,elemtype,elemdim,sideelements,material;
7020
int *moveelement=NULL,*parentorder=NULL,*possible=NULL,**invtopo=NULL;
7021
int noelements,maxpossible,noknots,maxelemsides,twiceelem,sideelemdim,minelemdim,maxelemdim;
7022
int debug,unmoved,removed,elemhits,loopdim,lowdimbulk;
7023
int notfound,*notfounds=NULL,movenames;
7024
7025
7026
if(info) {
7027
printf("Moving bulk elements to boundary elements\n");
7028
if(0) printf("Trying to retain orphans: %d\n",retainorphans);
7029
}
7030
7031
for(j=0;j < MAXBOUNDARIES;j++)
7032
bound[j].created = FALSE;
7033
for(j=0;j < MAXBOUNDARIES;j++)
7034
bound[j].nosides = 0;
7035
7036
noelements = data->noelements;
7037
noknots = data->noknots;
7038
7039
movenames = (data->bodynamesexist && !data->boundarynamesexist);
7040
if(data->bodynamesexist && info) {
7041
if(movenames)
7042
printf("Moving boundarynames together with elements\n");
7043
else
7044
printf("Assuming that boundaries names are already Ok!\n");
7045
}
7046
7047
maxelemtype = GetMaxElementType(data);
7048
if(info) printf("Leading bulk elementtype is %d\n",maxelemtype);
7049
7050
minelemtype = GetMinElementType(data);
7051
if(info) printf("Trailing bulk elementtype is %d\n",minelemtype);
7052
7053
maxelemdim = GetElementDimension(maxelemtype);
7054
minelemdim = GetElementDimension(minelemtype);
7055
if( maxelemdim - minelemdim == 0) {
7056
if(info) printf("No lower dimensional elements present!\n");
7057
return;
7058
}
7059
7060
if(maxelemdim-minelemdim > 1 ) {
7061
int **tagcount;
7062
int mintag,maxtag,tag,overlap;
7063
7064
mintag=maxtag=tag=overlap=-1;
7065
7066
if(info) printf("Checking that different dimensions have unique boundary tags!\n");
7067
7068
for(k=0;k<=2;k++) {
7069
for(i=1;i<=noelements;i++) {
7070
elemdim = GetElementDimension(data->elementtypes[i]);
7071
tag = data->material[i];
7072
7073
/* Get the tag interval for all elements */
7074
if(k==0) {
7075
if(maxtag==-1) {
7076
mintag = maxtag = tag;
7077
}
7078
else {
7079
mintag = MIN(mintag,tag);
7080
maxtag = MAX(maxtag,tag);
7081
}
7082
}
7083
7084
/* Count the number of tags for each dimensional */
7085
else if(k==1) {
7086
tagcount[elemdim][tag] += 1;
7087
}
7088
7089
/* Set the new tags for lower dimensions */
7090
else if(k==2) {
7091
if(elemdim < maxelemdim ) {
7092
data->material[i] = tagcount[elemdim][tag];
7093
}
7094
}
7095
}
7096
7097
if(k==0) {
7098
if(info) printf("Tag interval for boundaries: [%d %d]\n",mintag,maxtag);
7099
tagcount = Imatrix(0,maxelemdim,mintag,maxtag);
7100
for(i=0;i<=maxelemdim;i++)
7101
for(j=mintag;j<=maxtag;j++)
7102
tagcount[i][j] = 0;
7103
}
7104
else if(k==1) {
7105
for(j=mintag;j<=maxtag;j++) {
7106
overlap = 0;
7107
for(i=0;i<maxelemdim;i++)
7108
if(tagcount[i][j]) overlap++;
7109
if(overlap>1) break;
7110
}
7111
if(overlap>1) {
7112
if(info) printf("We have an overlap, applying offsets!\n");
7113
tag = 0;
7114
for(i=maxelemdim-1;i>=0;i--)
7115
for(j=mintag;j<=maxtag;j++) {
7116
if(tagcount[i][j]) {
7117
if(tag+1 <= j) {
7118
tag = j;
7119
}
7120
else {
7121
tag++;
7122
if(info) printf("Replacing tag in %d-dim %d -> %d\n",i,j,tag);
7123
}
7124
tagcount[i][j] = tag;
7125
}
7126
}
7127
}
7128
else {
7129
if(info) printf("No overlap, no offsets needed!\n");
7130
break;
7131
}
7132
}
7133
else if(k==2) {
7134
if(info) printf("Renumbered tags for boundary elements!\n");
7135
}
7136
}
7137
free_Imatrix(tagcount,0,maxelemdim,mintag,maxtag);
7138
}
7139
7140
moveelement = Ivector(1,noelements);
7141
7142
sideelements = 0;
7143
maxelemtype = 0;
7144
maxelemsides = 0;
7145
unmoved = 0;
7146
removed = 0;
7147
notfound = 0;
7148
lowdimbulk = 0;
7149
7150
for(i=1;i<=noelements;i++) {
7151
moveelement[i] = FALSE;
7152
sideelemdim = GetElementDimension(data->elementtypes[i]);
7153
7154
/* Lower dimensional elements are candidates to become BC elements */
7155
moveelement[i] = maxelemdim - sideelemdim;
7156
if(moveelement[i]) sideelements++;
7157
}
7158
if(info) printf("There are %d (out of %d) lower dimensional elements.\n",
7159
sideelements,noelements);
7160
if(sideelements == 0) return;
7161
7162
AllocateBoundary(bound,sideelements);
7163
7164
/* Compute maximum number of hits for inverse topology */
7165
possible = Ivector(1,noknots);
7166
for(i=1;i<=noknots;i++) possible[i] = 0;
7167
for(elemind=1;elemind <= data->noelements;elemind++) {
7168
/* if(moveelement[elemind]) continue; */
7169
elemtype = data->elementtypes[elemind];
7170
if(elemtype < 200 ) continue;
7171
for(i=0;i<data->elementtypes[elemind]%100;i++) {
7172
j = data->topology[elemind][i];
7173
possible[j] += 1;
7174
}
7175
}
7176
7177
j = 1;
7178
maxpossible = possible[1];
7179
for(i=1;i<=noknots;i++) {
7180
if(maxpossible < possible[i]) {
7181
maxpossible = possible[i];
7182
j = i;
7183
}
7184
}
7185
if(info) printf("Node %d belongs to maximum of %d elements\n",j,maxpossible);
7186
7187
/* Make a table showing to which elements a node belongs to
7188
Include only the potential parents which are not to be moved to BCs. */
7189
invtopo = Imatrix(1,noknots,1,maxpossible);
7190
for(i=1;i<=noknots;i++)
7191
for(j=1;j<=maxpossible;j++)
7192
invtopo[i][j] = 0;
7193
7194
for(elemind=1;elemind <= data->noelements;elemind++) {
7195
/* if(moveelement[elemind]) continue; */
7196
elemtype = data->elementtypes[elemind];
7197
if(elemtype < 200 ) continue;
7198
for(i=0;i<elemtype%100;i++) {
7199
k = data->topology[elemind][i];
7200
for(l=1;invtopo[k][l];l++);
7201
invtopo[k][l] = elemind;
7202
}
7203
}
7204
7205
sideelem = 0;
7206
sameelem = 0;
7207
twiceelem = 0;
7208
7209
debug = FALSE;
7210
7211
/* Go through boundary element candidates starting from higher dimension */
7212
for(loopdim=maxelemdim-1;loopdim>=0;loopdim--) {
7213
7214
if(debug) printf("loopdim = %d\n",loopdim);
7215
7216
for(elemind=1;elemind <= data->noelements;elemind++) {
7217
7218
if(!moveelement[elemind]) continue;
7219
7220
same = FALSE;
7221
sideelemtype = data->elementtypes[elemind];
7222
7223
/* Only check the elements that have right dimension */
7224
sideelemdim = GetElementDimension(sideelemtype);
7225
if(sideelemdim != loopdim ) continue;
7226
7227
sidenodes = sideelemtype % 100;
7228
for(i=0;i<sidenodes;i++)
7229
sideind[i] = data->topology[elemind][i];
7230
elemhits = 0;
7231
7232
if(debug) printf("Finding elem: %d %d %d\n",elemind,sideelemtype,sideelemdim);
7233
7234
7235
for(l=1;l<=maxpossible;l++) {
7236
elemind2 = invtopo[sideind[0]][l];
7237
7238
if(!elemind2) continue;
7239
7240
/* The parent should be an element that will not become BC element */
7241
if(moveelement[elemind2]) continue;
7242
7243
elemtype = data->elementtypes[elemind2];
7244
elemdim = GetElementDimension(elemtype);
7245
7246
/* Owner element should have higher dimension */
7247
if(elemdim <= sideelemdim ) continue;
7248
7249
hit = 0;
7250
for(i=0;i<sidenodes;i++)
7251
for(j=0;j<elemtype%100;j++)
7252
if(sideind[i] == data->topology[elemind2][j]) hit++;
7253
7254
if(hit < sidenodes) continue;
7255
7256
if(hit > sidenodes) printf("Strange: elemhits %d vs. elemnodes %d\n",hit,sidenodes);
7257
if(hit >= sidenodes) elemhits++;
7258
7259
for(side=0;side<=100;side++) {
7260
GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2);
7261
7262
if(sideelemtype2 == 0 ) break;
7263
7264
if(sideelemtype2 < 300 && sideelemtype > 300) break;
7265
if(sideelemtype2 < 200 && sideelemtype > 200) break;
7266
if(sideelemtype2 != sideelemtype ) continue;
7267
7268
sidenodes2 = sideelemtype2 % 100;
7269
if(sidenodes != sidenodes2) continue;
7270
if(sidenodes2 == 1 && sidenodes > 1) break;
7271
7272
hit = 0;
7273
for(i=0;i<sidenodes;i++)
7274
for(j=0;j<sidenodes2;j++)
7275
if(sideind[i] == sideind2[j]) hit++;
7276
7277
if(0) printf("%d hits in element %d\n",hit,sideelemtype2);
7278
if(hit == sidenodes) break;
7279
7280
if(sideelemtype != sideelemtype2) {
7281
printf("Hits in element after mismatch: %d vs. %d\n",sideelemtype,sideelemtype2);
7282
continue;
7283
}
7284
}
7285
if( sidenodes == 1 && !hit) {
7286
printf("elemind = %d sideind %d vs. ",elemind,sideind[0]);
7287
for(j=0;j<sidenodes2;j++)
7288
printf("%d ",sideind2[j]);
7289
printf("\n");
7290
}
7291
7292
if(hit < sidenodes || !sideelemtype2) {
7293
if(0) printf("Preliminary hit but not really: %d %d\n",hit,sidenodes);
7294
continue;
7295
}
7296
7297
if(same) {
7298
sameelem += 1;
7299
bound->parent2[sideelem] = elemind2;
7300
bound->side2[sideelem] = side;
7301
7302
if(debug) printf(" Found 2nd: %d %d %d\n",elemind,elemind2,side);
7303
goto foundtwo;
7304
}
7305
else {
7306
sideelem += 1;
7307
same = TRUE;
7308
if(debug) printf(" Found 1st: %d %d %d %d %d\n",elemind,elemind2,side,sideelemtype,sideelemtype2);
7309
7310
bound->parent[sideelem] = elemind2;
7311
bound->side[sideelem] = side;
7312
bound->parent2[sideelem] = 0;
7313
bound->side2[sideelem] = 0;
7314
material = data->material[elemind];
7315
bound->types[sideelem] = material;
7316
7317
if(sidenodes == 2) {
7318
if((sideind[0]-sideind[1])*(sideind2[0]-sideind2[1])<0)
7319
bound->normal[sideelem] = -1;
7320
}
7321
if(movenames) {
7322
data->boundarynamesexist = TRUE;
7323
if(material < MAXBODIES && material < MAXBCS) {
7324
if(!data->boundaryname[material]) {
7325
data->boundaryname[material] = Cvector(0,MAXNAMESIZE);
7326
if(data->bodyname[material]) {
7327
strcpy(data->boundaryname[material],data->bodyname[material]);
7328
free_Cvector(data->bodyname[material],0,MAXNAMESIZE);
7329
data->bodyname[material] = NULL;
7330
}
7331
else
7332
sprintf(data->boundaryname[material],"body%d",material);
7333
}
7334
}
7335
if(!strncmp(data->boundaryname[material],"body",4)) {
7336
strncpy(data->boundaryname[material],"bnry",4);
7337
}
7338
}
7339
7340
/* Only try to find two parents if the boundary element is one degree smaller than maximum dimension */
7341
if(moveelement[elemind] > 1) goto foundtwo;
7342
}
7343
}
7344
7345
if(!same) {
7346
/* If the element is of dimension DIM-1 then create a table showing where they are */
7347
if(retainorphans ) {
7348
/* If we have only one degree smaller unfound element then keep them as bulk elements. */
7349
if( moveelement[elemind] == 1) {
7350
moveelement[elemind] = 0;
7351
lowdimbulk++;
7352
if(debug) printf(" Bulk: %d\n",elemind);
7353
}
7354
else {
7355
if(!notfound) {
7356
notfounds = Ivector(1,noelements);
7357
for(i=1;i<=noelements;i++)
7358
notfounds[i] = FALSE;
7359
}
7360
notfound++;
7361
notfounds[elemind] = TRUE;
7362
7363
if(0) {
7364
printf("element: elemind = %d type = %d nodes = %d elemhits = %d\n",
7365
elemind,sideelemtype,sidenodes,elemhits);
7366
printf(" inds =");
7367
for(i=0;i<sidenodes;i++)
7368
printf(" %d ",sideind[i]);
7369
printf("\n");
7370
}
7371
7372
if(debug) printf(" Unfound: %d\n",elemind);
7373
}
7374
}
7375
else {
7376
if(debug) printf(" Removed: %d\n",elemind);
7377
7378
moveelement[elemind] = -1;
7379
removed += 1;
7380
}
7381
}
7382
7383
foundtwo:
7384
continue;
7385
7386
}
7387
7388
if(0) printf("Intermediate results: %d %d %d %d\n",twiceelem,sameelem,sideelem,removed);
7389
}
7390
7391
if(twiceelem) printf("Found %d sides that were multiply given\n",twiceelem);
7392
if(sameelem) printf("Found %d side elements that have two parents.\n",sameelem);
7393
7394
7395
if(sideelem == sideelements) {
7396
printf("Found correctly %d side elements.\n",sideelem);
7397
}
7398
else {
7399
printf("Studied %d lower dimensional elements\n",sideelements);
7400
printf("Defined %d side elements\n",sideelem);
7401
printf("Defined %d lower dimensional bulk elements\n",lowdimbulk);
7402
7403
bound->nosides = sideelem;
7404
7405
printf("Removing %d lower dimensional elements from the element list\n",removed);
7406
if(notfound) {
7407
if(0) printf("************************** WARNING **********************\n");
7408
if(retainorphans) {
7409
printf("Adding %d elements to boundary without parent information\n",notfound);
7410
7411
bound->elementtypes = Ivector(sideelem+1,sideelements);
7412
for(i=sideelem+1;i<=sideelements;i++) bound->elementtypes[i] = 0;
7413
7414
bound->topology = Imatrix(sideelem+1,sideelements,0,MAXNODESD2-1);
7415
7416
for(elemind=1;elemind <= data->noelements;elemind++) {
7417
if(!notfounds[elemind]) continue;
7418
sideelem++;
7419
7420
j = data->elementtypes[elemind];
7421
bound->elementtypes[sideelem] = j;
7422
7423
for(i=0;i<j%100;i++)
7424
bound->topology[sideelem][i] = data->topology[elemind][i];
7425
7426
/* Adding some constant here could be used for debugging */
7427
bound->types[sideelem] = data->material[elemind] + 1*10;
7428
bound->parent[sideelem] = 0;
7429
}
7430
bound->nosides = sideelem;
7431
}
7432
else {
7433
printf("Removing %d lower dimensional elements without parent information\n",notfound);
7434
}
7435
}
7436
}
7437
7438
/* Reorder remaining bulk elements */
7439
parentorder = Ivector(1,noelements);
7440
for(i=1;i<=noelements;i++)
7441
parentorder[i] = 0;
7442
7443
j = 0;
7444
for(i=1;i<=noelements;i++) {
7445
if(moveelement[i] == 0) {
7446
k = data->elementtypes[i];
7447
7448
j++;
7449
parentorder[i] = j;
7450
7451
if(debug) printf("Bulk is: %d %d\n",i,j);
7452
7453
if( i != j ) {
7454
data->material[j] = data->material[i];
7455
data->elementtypes[j] = data->elementtypes[i];
7456
for(l=0;l<k%100;l++)
7457
data->topology[j][l] = data->topology[i][l];
7458
}
7459
}
7460
}
7461
data->noelements = j;
7462
if(info) printf("Parent elements were reordered up to index %d.\n",j);
7463
7464
7465
/* Reorder boundary to point at the new arrangement of master elements */
7466
for(i=1;i<=bound->nosides;i++) {
7467
if(!bound->parent[i]) continue;
7468
7469
if( !parentorder[bound->parent[i]] ) {
7470
printf("Zero reorder: %d %d %d\n",i,bound->parent[i],bound->side[i]);
7471
bigerror("Sorry folks!");
7472
}
7473
7474
if(bound->parent[i]) bound->parent[i] = parentorder[bound->parent[i]];
7475
if(bound->parent2[i]) bound->parent2[i] = parentorder[bound->parent2[i]];
7476
7477
GetElementSide(bound->parent[i],bound->side[i],1,data,&sideind2[0],&sideelemtype2);
7478
7479
if(0) GetBoundaryElement(i,&bound[j],data,&sideind2[0],&sideelemtype2);
7480
}
7481
7482
if(info) printf("Moved %d elements (out of %d) to new positions\n",j,noelements);
7483
7484
free_Ivector(parentorder,1,noelements);
7485
7486
free_Ivector(moveelement,1,noelements);
7487
free_Ivector(possible,1,noknots);
7488
free_Imatrix(invtopo,1,noknots,1,maxpossible);
7489
if(notfound) free_Ivector(notfounds,1,noelements);
7490
7491
if(debug) printf("All done\n");
7492
7493
return;
7494
}
7495
7496
7497
int SideAndBulkMappings(struct FemType *data,struct BoundaryType *bound,struct ElmergridType *eg,int info)
7498
{
7499
int i,j,l,currenttype;
7500
7501
7502
if(eg->sidemappings) {
7503
if(info) printf("Renumbering boundary types with %d mappings\n",eg->sidemappings);
7504
7505
for(l=0;l<eg->sidemappings;l++)
7506
if(info) printf("Setting boundary types between %d and %d to %d\n",
7507
eg->sidemap[3*l],eg->sidemap[3*l+1],eg->sidemap[3*l+2]);
7508
7509
for(j=0;j < MAXBOUNDARIES;j++) {
7510
if(!bound[j].created) continue;
7511
7512
for(i=1; i <= bound[j].nosides; i++) {
7513
if((currenttype = bound[j].types[i])) {
7514
for(l=0;l<eg->sidemappings;l++) {
7515
if(currenttype >= eg->sidemap[3*l] && currenttype <= eg->sidemap[3*l+1]) {
7516
bound[j].types[i] = eg->sidemap[3*l+2];
7517
currenttype = -1;
7518
}
7519
}
7520
}
7521
}
7522
}
7523
if(info) printf("Renumbering boundary types finished\n");
7524
}
7525
7526
if(eg->bulkmappings) {
7527
if(info) printf("Renumbering bulk types with %d mappings\n",eg->bulkmappings);
7528
7529
for(l=0;l<eg->bulkmappings;l++)
7530
if(info) printf("Setting material types between %d and %d to %d\n",
7531
eg->bulkmap[3*l],eg->bulkmap[3*l+1],eg->bulkmap[3*l+2]);
7532
for(j=1;j<=data->noelements;j++) {
7533
currenttype = data->material[j];
7534
for(l=0;l<eg->bulkmappings;l++) {
7535
if(currenttype >= eg->bulkmap[3*l] && currenttype <= eg->bulkmap[3*l+1]) {
7536
data->material[j] = eg->bulkmap[3*l+2];
7537
currenttype = -1;
7538
}
7539
}
7540
}
7541
if(info) printf("Renumbering material indexes finished\n");
7542
}
7543
return(0);
7544
}
7545
7546
7547
7548
int SideAndBulkBoundaries(struct FemType *data,struct BoundaryType *bound,struct ElmergridType *eg,int info)
7549
{
7550
int l;
7551
int *boundnodes,noboundnodes;
7552
boundnodes = Ivector(1,data->noknots);
7553
7554
if(eg->bulkbounds) {
7555
for(l=0;l<eg->bulkbounds;l++) {
7556
FindBulkBoundary(data,eg->bulkbound[3*l],eg->bulkbound[3*l+1],
7557
boundnodes,&noboundnodes,info);
7558
FindNewBoundaries(data,bound,boundnodes,eg->bulkbound[3*l+2],1,info);
7559
}
7560
}
7561
if(eg->boundbounds) {
7562
for(l=0;l<eg->boundbounds;l++) {
7563
FindBoundaryBoundary(data,bound,eg->boundbound[3*l],eg->boundbound[3*l+1],
7564
boundnodes,&noboundnodes,info);
7565
FindNewBoundaries(data,bound,boundnodes,eg->boundbound[3*l+2],2,info);
7566
}
7567
}
7568
free_Ivector(boundnodes,1,data->noknots);
7569
7570
return(0);
7571
}
7572
7573
7574
void NodesToBoundaryChain(struct FemType *data,struct BoundaryType *bound,
7575
int *bcinds,int *bctags,int nbc,int bccount,
7576
int info)
7577
{
7578
int i,j,k,l,sideelemtype,sideelemtype2,elemind,elemind2,sideelem,sameelem;
7579
int sideind[MAXNODESD1],sideind2[MAXNODESD1],elemsides,side,hit,same,minelemtype;
7580
int sidenodes,sidenodes2,elemtype,elemdim,sideelements,material;
7581
int *possible=NULL,**invtopo=NULL;
7582
int noelements,maxpossible,noknots,twiceelem,sideelemdim;
7583
int elemhits,bci;
7584
7585
7586
if(info) printf("Creating boundary elements from boundary nodes\n");
7587
7588
for(j=0;j < MAXBOUNDARIES;j++)
7589
bound[j].created = FALSE;
7590
for(j=0;j < MAXBOUNDARIES;j++)
7591
bound[j].nosides = 0;
7592
7593
noelements = data->noelements;
7594
noknots = data->noknots;
7595
7596
sideelements = nbc - bccount;
7597
printf("Expected number of BC elements: %d\n",sideelements);
7598
7599
AllocateBoundary(bound,sideelements);
7600
7601
/* Calculate how may times a node appears */
7602
possible = Ivector(1,noknots);
7603
for(i=1;i<=noknots;i++) possible[i] = 0;
7604
for(elemind=1;elemind <= data->noelements;elemind++) {
7605
for(i=0;i<data->elementtypes[elemind]%100;i++) {
7606
j = data->topology[elemind][i];
7607
possible[j] += 1;
7608
}
7609
}
7610
7611
j = 1;
7612
maxpossible = possible[1];
7613
for(i=1;i<=noknots;i++) {
7614
if(maxpossible < possible[i]) {
7615
maxpossible = possible[i];
7616
j = i;
7617
}
7618
}
7619
if(info) printf("Node %d belongs to maximum of %d elements\n",j,maxpossible);
7620
7621
/* Make a table showing to which elements a node belongs to
7622
Include only the potential parents which are not to be moved to BCs. */
7623
invtopo = Imatrix(1,noknots,1,maxpossible);
7624
7625
for(i=1;i<=noknots;i++)
7626
for(j=1;j<=maxpossible;j++)
7627
invtopo[i][j] = 0;
7628
7629
for(elemind=1;elemind <= data->noelements;elemind++) {
7630
elemtype = data->elementtypes[elemind];
7631
for(i=0;i<elemtype%100;i++) {
7632
k = data->topology[elemind][i];
7633
for(l=1;invtopo[k][l];l++); /* Yes, this is really ok. We look for unset entry. */
7634
invtopo[k][l] = elemind;
7635
}
7636
}
7637
7638
sideelem = 0;
7639
sameelem = 0;
7640
twiceelem = 0;
7641
7642
/* These are here by construction because we are looking for a chain of nodes
7643
and trying to create 202 elements of them! */
7644
sidenodes = 2;
7645
sideelemtype = 202;
7646
7647
for(bci=1;bci<nbc;bci++) {
7648
7649
same = FALSE;
7650
7651
if( bctags[bci] != bctags[bci+1] ) continue;
7652
7653
sideind[0] = bcinds[bci];
7654
sideind[1] = bcinds[bci+1];
7655
material = bctags[bci];
7656
7657
elemhits = 0;
7658
7659
/* Go through potential parents elements using the inverse topology */
7660
for(l=1;l<=maxpossible;l++) {
7661
elemind2 = invtopo[sideind[0]][l];
7662
7663
if(!elemind2) continue;
7664
7665
elemtype = data->elementtypes[elemind2];
7666
hit = 0;
7667
for(i=0;i<sidenodes;i++)
7668
for(j=0;j<elemtype%100;j++)
7669
if(sideind[i] == data->topology[elemind2][j]) hit++;
7670
7671
/* We must have all hits to have a chance of finding bc */
7672
if(hit < sidenodes) continue;
7673
7674
elemhits++;
7675
7676
/* Now find on which side the bc is */
7677
for(side=0;side<3;side++) {
7678
GetElementSide(elemind2,side,1,data,&sideind2[0],&sideelemtype2);
7679
if( sideelemtype2 != sideelemtype ) printf("This should not happen!\n");
7680
7681
hit = 0;
7682
for(i=0;i<sidenodes;i++)
7683
for(j=0;j<sidenodes;j++)
7684
if(sideind[i] == sideind2[j]) hit++;
7685
7686
if(hit < sidenodes) continue;
7687
7688
if(same) {
7689
/* Ok, we found the other parent for this already */
7690
sameelem += 1;
7691
bound->parent2[sideelem] = elemind2;
7692
bound->side2[sideelem] = side;
7693
goto foundtwo;
7694
}
7695
else {
7696
/* We haven't found parents for this bc elements yet */
7697
sideelem += 1;
7698
same = TRUE;
7699
bound->parent[sideelem] = elemind2;
7700
bound->side[sideelem] = side;
7701
bound->parent2[sideelem] = 0;
7702
bound->side2[sideelem] = 0;
7703
bound->types[sideelem] = material;
7704
if(sidenodes == 2) {
7705
if((sideind[0]-sideind[1])*(sideind2[0]-sideind2[1])<0)
7706
bound->normal[sideelem] = -1;
7707
}
7708
}
7709
}
7710
}
7711
foundtwo:
7712
continue;
7713
}
7714
7715
if(twiceelem) printf("Found %d sides that were multiply given\n",twiceelem);
7716
if(sameelem) printf("Found %d side elements that have two parents.\n",sameelem);
7717
7718
7719
if(sideelem == sideelements) {
7720
printf("Found correctly %d side elements.\n",sideelem);
7721
}
7722
else {
7723
printf("Found %d side elements, could have found %d\n",sideelem,sideelements);
7724
}
7725
7726
bound->nosides = sideelem;
7727
7728
free_Ivector(possible,1,noknots);
7729
free_Imatrix(invtopo,1,noknots,1,maxpossible);
7730
7731
return;
7732
}
7733
7734
7735
7736
7737
int FindPeriodicNodes(struct FemType *data,int periodicdim[],int info)
7738
{
7739
int i,j,i2,j2,dim;
7740
int noknots,hit,tothits;
7741
int *topbot=NULL,*indxper=NULL;
7742
int botn,topn,*revindtop=NULL,*revindbot=NULL;
7743
Real eps,dist,dx,dy,dz,coordmax,coordmin;
7744
Real *coord=NULL,*toparr=NULL,*botarr=NULL,epsmin;
7745
7746
7747
if(data->dim < 3) periodicdim[2] = 0;
7748
if(!periodicdim[0] && !periodicdim[1] && !periodicdim[2]) return(1);
7749
7750
if(data->periodicexist) {
7751
printf("FindPeriodicNodes: Subroutine is called for second time?\n");
7752
return(2);
7753
}
7754
7755
noknots = data->noknots;
7756
tothits = 0;
7757
7758
data->periodicexist = TRUE;
7759
indxper = Ivector(1,noknots);
7760
data->periodic = indxper;
7761
topbot = Ivector(1,noknots);
7762
7763
7764
for(i=1;i<=noknots;i++)
7765
indxper[i] = i;
7766
7767
for(dim=1;dim<=3;dim++) {
7768
if(!periodicdim[dim-1]) continue;
7769
7770
if(info) printf("Finding periodic nodes in direction %d\n",dim);
7771
7772
if(dim==1) coord = data->x;
7773
else if(dim==2) coord = data->y;
7774
else coord = data->z;
7775
7776
coordmax = coordmin = coord[1];
7777
7778
for(i=1;i<=data->noknots;i++) {
7779
if(coordmax < coord[i]) coordmax = coord[i];
7780
if(coordmin > coord[i]) coordmin = coord[i];
7781
}
7782
7783
if(info) printf("Coordinate in dimension %d is at the interval [%.3lg, %.3lg]\n",
7784
dim,coordmin,coordmax);
7785
7786
if(coordmax-coordmin < 1.0e-10) continue;
7787
eps = 1.0e-5 * (coordmax-coordmin);
7788
7789
topn = botn = 0;
7790
for(i=1;i<=data->noknots;i++) {
7791
if(fabs(coord[i]-coordmax) < eps) {
7792
topn++;
7793
topbot[i] = topn;
7794
}
7795
else if(fabs(coord[i] - coordmin) < eps) {
7796
botn++;
7797
topbot[i] = -botn;
7798
}
7799
else {
7800
topbot[i] = 0;
7801
}
7802
}
7803
7804
if(topn != botn) {
7805
printf("There should be equal number of top and bottom nodes (%d vs. %d)!\n",topn,botn);
7806
return(3);
7807
}
7808
else {
7809
if(info) printf("Looking for %d periodic nodes\n",topn);
7810
}
7811
7812
toparr = Rvector(1,topn);
7813
botarr = Rvector(1,botn);
7814
revindtop = Ivector(1,topn);
7815
revindbot = Ivector(1,botn);
7816
7817
topn = botn = 0;
7818
for(i=1;i<=noknots;i++) {
7819
j = topbot[i];
7820
if(j > 0) {
7821
topn++;
7822
revindtop[topn] = i;
7823
}
7824
else if(j < 0) {
7825
j = abs(j);
7826
botn++;
7827
revindbot[botn] = i;
7828
}
7829
}
7830
7831
if(data->dim == 2) {
7832
for(i=1;i<=botn;i++) {
7833
j = revindbot[i];
7834
hit = FALSE;
7835
for(i2=1;i2<=topn;i2++) {
7836
j2 = revindtop[i2];
7837
if(dim == 1)
7838
dist = fabs(data->y[j] - data->y[j2]);
7839
else
7840
dist = fabs(data->x[j] - data->x[j2]);
7841
if(dist < eps) {
7842
hit = TRUE;
7843
goto hit2d;
7844
}
7845
}
7846
7847
hit2d:
7848
if(hit) {
7849
tothits++;
7850
if(indxper[j] == j) indxper[j2] = j;
7851
else if(indxper[indxper[j]]==indxper[j]) {
7852
indxper[j2] = indxper[j];
7853
}
7854
else {
7855
printf("unknown 2d case!\n");
7856
}
7857
}
7858
else {
7859
printf("Couldn't find a periodic counterpart for node %d at [%.3lg %.3lg]]\n",
7860
j,data->x[j],data->y[j]);
7861
}
7862
}
7863
}
7864
else if(data->dim == 3) {
7865
dx = dy = dz = 0.0;
7866
for(i=1;i<=botn;i++) {
7867
j = revindbot[i];
7868
hit = FALSE;
7869
epsmin = coordmax - coordmin;
7870
7871
for(i2=1;i2<=topn;i2++) {
7872
j2 = revindtop[i2];
7873
if(dim == 1) {
7874
dy = data->y[j] - data->y[j2];
7875
dz = data->z[j] - data->z[j2];
7876
}
7877
else if(dim == 2) {
7878
dx = data->x[j] - data->x[j2];
7879
dz = data->z[j] - data->z[j2];
7880
}
7881
else {
7882
dx = data->x[j] - data->x[j2];
7883
dy = data->y[j] - data->y[j2];
7884
}
7885
if(dx*dx+dy*dy+dz*dz < eps*eps) {
7886
hit = TRUE;
7887
goto hit3d;
7888
}
7889
}
7890
7891
hit3d:
7892
if(hit) {
7893
tothits++;
7894
indxper[j2] = indxper[j];
7895
}
7896
else {
7897
printf("The periodic counterpart for node %d was not found!\n",j);
7898
}
7899
}
7900
}
7901
7902
free_Rvector(toparr,1,topn);
7903
free_Rvector(botarr,1,botn);
7904
free_Ivector(revindtop,1,topn);
7905
free_Ivector(revindbot,1,botn);
7906
}
7907
7908
if(info) printf("Found all in all %d periodic nodes.\n",tothits);
7909
7910
free_Ivector(topbot,1,noknots);
7911
7912
return(0);
7913
}
7914
7915
7916
7917
7918
int FindPeriodicParents(struct FemType *data,struct BoundaryType *bound,int info)
7919
{
7920
int i,j,k,k2,l,l2,totsides,newsides,sidenodes,sideelemtype,side;
7921
int noknots,maxhits,nodes,hits,hits2,targets,mappings,targetnode;
7922
int parent,parent2,sideind[MAXNODESD1],sideind2[MAXNODESD1];
7923
int **periodicparents=NULL, *periodichits=NULL,*periodictarget=NULL,*indexper=NULL;
7924
7925
totsides = 0;
7926
newsides = 0;
7927
targets = 0;
7928
parent2 = 0;
7929
7930
if(info) printf("Finding secondary periodic parents for boundary elements\n");
7931
7932
if(!data->periodicexist) {
7933
printf("FindPeriodicParents: Periodic nodes are not defined\n");
7934
return(2);
7935
}
7936
7937
indexper = data->periodic;
7938
7939
/* Set pointers that point to the periodic nodes */
7940
noknots = data->noknots;
7941
periodictarget = Ivector(1,noknots);
7942
for(i=1;i<=noknots;i++)
7943
periodictarget[i] = 0;
7944
7945
mappings = 0;
7946
for(i=1;i<=noknots;i++) {
7947
j = indexper[i];
7948
if( j != i) {
7949
mappings++;
7950
periodictarget[j] = i;
7951
}
7952
}
7953
7954
if(0) for(i=1;i<=noknots;i++)
7955
printf("indexes(%d) : %d %d\n",i,indexper[i],periodictarget[i]);
7956
7957
7958
if(info) printf("Number of potential periodic mappings is %d\n",mappings);
7959
for(i=1;i<=noknots;i++)
7960
if(periodictarget[i]) targets++;
7961
if(info) printf("Number of potential periodic targets is %d\n",targets);
7962
7963
7964
/* Vector telling how many elements are associated with the periodic nodes */
7965
maxhits = 0;
7966
periodichits = Ivector(1,noknots);
7967
for(i=1;i<=noknots;i++)
7968
periodichits[i] = 0;
7969
7970
/* Create the matrix telling which elements are associated with the periodic nodes */
7971
setparents:
7972
for(j=1;j <= data->noelements;j++) {
7973
nodes = data->elementtypes[j] % 100;
7974
for(i=0;i<nodes;i++) {
7975
k = data->topology[j][i];
7976
if( k != indexper[k] ) {
7977
periodichits[k] += 1;
7978
if( maxhits > 0 ) {
7979
periodicparents[k][periodichits[k]] = j;
7980
}
7981
}
7982
}
7983
}
7984
7985
if( maxhits == 0 ) {
7986
for(i=1;i<=noknots;i++)
7987
maxhits = MAX( maxhits, periodichits[i] );
7988
7989
printf("Maximum number of elements associated with periodic nodes is %d\n",maxhits);
7990
periodicparents = Imatrix(1,noknots,1,maxhits);
7991
for(i=1;i<=noknots;i++) {
7992
periodichits[i] = 0;
7993
for(j=1;j<=maxhits;j++)
7994
periodicparents[i][j] = 0;
7995
}
7996
goto setparents;
7997
}
7998
7999
for(j=0;j<MAXBOUNDARIES;j++) {
8000
if(!bound[j].created) continue;
8001
if(!bound[j].nosides) continue;
8002
8003
for(i=1;i<=bound[j].nosides;i++) {
8004
8005
/* If secondary parent already set skip */
8006
if(bound[j].parent2[i]) continue;
8007
8008
parent = bound[j].parent[i];
8009
if(0) printf("1st parent %d\n",parent);
8010
8011
side = bound[j].side[i];
8012
8013
GetElementSide(parent,side,1,data,sideind,&sideelemtype);
8014
sidenodes = sideelemtype % 100;
8015
8016
/* Some node must be periodic target and others either target or mapped nodes */
8017
hits = hits2 = 0;
8018
for(k=0;k<sidenodes;k++) {
8019
l = sideind[k];
8020
if( periodictarget[l] )
8021
hits++;
8022
else if(indexper[l] != l)
8023
hits2++;
8024
}
8025
if(!hits || hits + hits2 < sidenodes) continue;
8026
8027
if(0) printf("Trying to find other parent for boundary %d and parent %d\n",
8028
bound[j].types[i],parent);
8029
if(0) printf("hits = %d %d %d\n",hits,hits2,sidenodes);
8030
8031
totsides++;
8032
8033
/* The parent is the one element that has exactly the same set of periodic nodes */
8034
for(l=0;l<sidenodes;l++) {
8035
targetnode = periodictarget[sideind[l]];
8036
if(!targetnode) continue;
8037
8038
for(l2=1;l2<=periodichits[targetnode];l2++) {
8039
int side,elemtype,elemsides,sideelemtype2;
8040
8041
parent2 = periodicparents[targetnode][l2];
8042
if(parent == parent2) continue;
8043
8044
elemtype = data->elementtypes[parent2];
8045
elemsides = GetElementFaces(elemtype);
8046
8047
for(side=0;side<elemsides;side++) {
8048
GetElementSide(parent2,side,1,data,sideind2,&sideelemtype2);
8049
if( sideelemtype != sideelemtype2 ) continue;
8050
8051
hits = 0;
8052
for(k=0;k<sidenodes;k++) {
8053
for(k2=0;k2<sidenodes;k2++) {
8054
if( indexper[sideind[k]] == indexper[sideind2[k2]]) {
8055
hits++;
8056
break;
8057
}
8058
}
8059
}
8060
if(hits == sidenodes) goto found;
8061
}
8062
}
8063
}
8064
8065
found:
8066
if(hits == sidenodes) {
8067
newsides++;
8068
if(0) printf("Parents joined by boundary element: %d %d\n",parent,parent2);
8069
bound[j].parent2[i] = -parent2;
8070
}
8071
else {
8072
printf("Could not find a periodic counterpart: %d/%d/%d\n",j,i,parent);
8073
printf("ind = %d ",sideind[0]);
8074
for(k=1;k<sidenodes;k++)
8075
printf("%d ",sideind[k]);
8076
printf("\n");
8077
}
8078
}
8079
}
8080
8081
free_Ivector(periodictarget,1,noknots);
8082
free_Ivector(periodichits,1,noknots);
8083
free_Imatrix(periodicparents,1,noknots,1,maxhits);
8084
8085
if(info) printf("Found %d secondary parents for %d potential sides.\n",newsides,totsides);
8086
return(0);
8087
}
8088
8089
8090
8091
8092
int CreateBoundaryLayer(struct FemType *data,struct BoundaryType *bound,
8093
int nolayers, int *layerbounds, int *layernumber,
8094
Real *layerratios, Real *layerthickness, int *layerparents,
8095
int maxfilters, Real layereps, int info)
8096
/* Create Boundary layers that may be used to solve accurately fluid
8097
flow problems and similar equations. */
8098
{
8099
int i,j,k,l,m,n,i2,i3,nonodes,maxbc,newbc;
8100
int noknots,noelements,elemindx,nodeindx,elemtype;
8101
int oldnoknots,oldnoelements,maxelemtype,oldmaxnodes;
8102
int nonewnodes,nonewelements,dolayer,dim,order,midpoints;
8103
int checkmaterials,parent,parent2,use2,second;
8104
Real dx,dy,ds,ratio,q,p,rectfactor;
8105
Real *newx=NULL,*newy=NULL,*newz=NULL,*oldx=NULL,*oldy=NULL,*elemwidth=NULL;
8106
Real e1x,e1y,e2x,e2y;
8107
int sideelemtype,ind[MAXNODESD2],sidebc[MAXNODESD1];
8108
int *layernode=NULL,*newelementtypes=NULL,**newtopo=NULL,**oldtopo=NULL;
8109
int *topomap=NULL,*newmaterial=NULL,*herit=NULL,*inside=NULL,*nonlin=NULL;
8110
int endbcs, *endparents=NULL, *endtypes=NULL, *endnodes=NULL, *endnodes2=NULL, *endneighbours=NULL;
8111
8112
if(0) printf("maxfilters=%d layereps=%.3e\n",maxfilters,layereps);
8113
8114
if(!maxfilters) maxfilters = 1000;
8115
if(layereps < 1.0e-20) layereps = 1.0e-3;
8116
rectfactor = 1.0e2;
8117
midpoints = FALSE;
8118
order = 1;
8119
dim = data->dim;
8120
8121
maxelemtype = GetMaxElementType(data);
8122
if(maxelemtype > 409) {
8123
printf("Subroutine implemented only up to 2nd degree in 2D!\n");
8124
bigerror("Cannot continue");
8125
}
8126
8127
if(info) printf("Largest elementtype is %d\n",maxelemtype);
8128
8129
second = FALSE;
8130
checkmaterials = FALSE;
8131
for(k=0;k<nolayers;k++)
8132
if(layerparents[k]) checkmaterials = TRUE;
8133
8134
8135
omstart:
8136
8137
oldnoelements = noelements = data->noelements;
8138
oldnoknots = noknots = data->noknots;
8139
oldmaxnodes = data->maxnodes;
8140
8141
layernode = Ivector(1,oldnoknots);
8142
for(i=1;i<=oldnoknots;i++) layernode[i] = 0;
8143
8144
8145
/* Go through all the boundaries with boundary layer definitions and compute
8146
the number of new nodes and new elements. */
8147
nonewnodes = 0;
8148
nonewelements = 0;
8149
maxbc = 0;
8150
8151
/* Go through the layers and check which ones are active */
8152
for(j=0;j<MAXBOUNDARIES;j++) {
8153
if(!bound[j].created) continue;
8154
8155
for(i=1;i<=bound[j].nosides;i++) {
8156
dolayer = FALSE;
8157
parent = bound[j].parent[i];
8158
use2 = FALSE;
8159
if(bound[j].types[i] > maxbc) maxbc = bound[j].types[i];
8160
8161
for(k=0;k<nolayers;k++) {
8162
8163
if(bound[j].types[i] == layerbounds[k]) {
8164
if(checkmaterials) {
8165
if(layerparents[k] < 0) continue;
8166
8167
if(data->material[parent] == layerparents[k])
8168
dolayer = k + 1;
8169
else if((parent = bound[j].parent2[i])) {
8170
if(data->material[parent] == layerparents[k]) {
8171
use2 = TRUE;
8172
dolayer = k + 1;
8173
}
8174
}
8175
}
8176
else {
8177
dolayer = k + 1;
8178
}
8179
}
8180
}
8181
8182
if(!dolayer) continue;
8183
8184
8185
/* We have found an boundary element to extrude */
8186
if(use2)
8187
GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],
8188
data,ind,&sideelemtype);
8189
else
8190
GetElementSide(parent,bound[j].side[i],bound[j].normal[i],
8191
data,ind,&sideelemtype);
8192
8193
nonewelements += layernumber[dolayer-1];
8194
8195
midpoints = FALSE;
8196
if(sideelemtype == 202) {
8197
order = 1;
8198
}
8199
else if(sideelemtype == 203) {
8200
order = 2;
8201
if(maxelemtype > 408) midpoints = TRUE;
8202
}
8203
8204
for(l=0;l<sideelemtype%100;l++) {
8205
8206
/* No layer has yet been created for this node */
8207
if(!layernode[ind[l]]) {
8208
8209
layernode[ind[l]] = -(noknots + nonewnodes);
8210
8211
if(l < sideelemtype/100 || midpoints)
8212
nonewnodes += order * layernumber[dolayer-1];
8213
else
8214
nonewnodes += layernumber[dolayer-1];
8215
}
8216
else {
8217
layernode[ind[l]] = abs(layernode[ind[l]]);
8218
}
8219
}
8220
}
8221
}
8222
8223
if(!nonewelements) {
8224
if(info) printf("Found no active boundary layers!\n");
8225
return(0);
8226
}
8227
8228
/* For higher order elements remove the middlenodes from the list of cornernodes */
8229
if(maxelemtype%100 > 4) {
8230
for(j=1;j<=noelements;j++) {
8231
elemtype = data->elementtypes[j];
8232
for(i=elemtype/100;i<elemtype%100;i++) {
8233
k = data->topology[j][i];
8234
layernode[k] = abs(layernode[k]);
8235
}
8236
}
8237
}
8238
8239
8240
/* Negative indexed means that the node is an end node of the newly created boundary */
8241
endbcs = 0;
8242
for(i=1;i<=noknots;i++)
8243
if(layernode[i] < 0) endbcs++;
8244
8245
if(endbcs) {
8246
endparents = Ivector(1,endbcs);
8247
endtypes = Ivector(1,endbcs);
8248
endnodes = Ivector(1,endbcs);
8249
endnodes2 = Ivector(1,endbcs);
8250
8251
endneighbours = Ivector(1,2*endbcs);
8252
for(i=1;i<=endbcs;i++)
8253
endparents[i] = endtypes[i] = endnodes[i] = endnodes2[i] = 0;
8254
8255
endbcs = 0;
8256
for(i=1;i<=noknots;i++) {
8257
if(layernode[i] < 0) {
8258
endbcs++;
8259
endparents[endbcs] = i;
8260
}
8261
}
8262
}
8263
8264
8265
/* Check if the new boundary is already connected to some one,
8266
however it must be different from the extruded boundary */
8267
for(i2=1;i2<=endbcs;i2++) {
8268
for(j=0;j<MAXBOUNDARIES;j++) {
8269
if(!bound[j].created) continue;
8270
8271
for(i=1;i<=bound[j].nosides;i++) {
8272
8273
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8274
data,ind,&sideelemtype);
8275
8276
/* Check that the node is one of the single nodes */
8277
dolayer = FALSE;
8278
for(i3=0;i3<sideelemtype%100;i3++)
8279
if(ind[i3] == endparents[i2]) {
8280
dolayer = TRUE;
8281
break;
8282
}
8283
if(!dolayer) continue;
8284
8285
/* First check that the found boundary has a correct parent material */
8286
dolayer = FALSE;
8287
if(checkmaterials) {
8288
for(k=0;k<nolayers;k++) {
8289
if(layerparents[k] < 0) continue;
8290
parent = bound[j].parent[i];
8291
if(data->material[parent] == layerparents[k])
8292
dolayer = TRUE;
8293
else if((parent = bound[j].parent2[i])) {
8294
if(data->material[parent] == layerparents[k]) {
8295
dolayer = TRUE;
8296
}
8297
}
8298
}
8299
}
8300
if(!dolayer) continue;
8301
8302
/* Finally check that this is not one of the extruded boundaries */
8303
dolayer = FALSE;
8304
for(k=0;k<nolayers;k++) {
8305
if(layerparents[k] < 0) continue;
8306
if(bound[j].types[i] == layerbounds[k]) dolayer = TRUE;
8307
}
8308
if(dolayer) {
8309
endneighbours[2*i2-1] = ind[1-i3];
8310
continue;
8311
}
8312
8313
endtypes[i2] = bound[j].types[i];
8314
dx = fabs(data->x[ind[0]] - data->x[ind[1]]);
8315
dy = fabs(data->y[ind[0]] - data->y[ind[1]]);
8316
8317
if(dx < rectfactor * dy && dy < rectfactor * dx) {
8318
endnodes[i2] = ind[i3];
8319
if(sideelemtype%100 > 2) endnodes2[i2] = ind[2];
8320
endneighbours[2*i2] = ind[1-i3];
8321
}
8322
8323
if(info) printf("Found an existing boundary %d for the single node %d %d\n",
8324
bound[j].types[i],endparents[i2],endnodes[i2]);
8325
8326
goto foundbc;
8327
}
8328
}
8329
8330
foundbc:
8331
8332
if(!endtypes[i2]) {
8333
maxbc++;
8334
endtypes[i2] = maxbc;
8335
}
8336
}
8337
8338
8339
/* Find the first unused bc */
8340
for(j=0;j<MAXBOUNDARIES;j++)
8341
if(!bound[j].created) {
8342
newbc = j;
8343
bound[newbc].nosides = 0;
8344
break;
8345
}
8346
8347
/* Find the maximum of layers */
8348
i = 0;
8349
for(k=0;k<nolayers;k++)
8350
if(layernumber[k] > i) i = layernumber[k];
8351
8352
if(endbcs) {
8353
if(info) {
8354
printf("Allocating for additional %d boundary elements into bc %d.\n",
8355
bound[newbc].nosides,newbc);
8356
}
8357
AllocateBoundary(&bound[newbc],i*endbcs);
8358
bound[newbc].created = FALSE;
8359
bound[newbc].nosides = 0;
8360
}
8361
8362
8363
/* The size of new mesh */
8364
noknots = data->noknots + nonewnodes;
8365
noelements = data->noelements + nonewelements;
8366
8367
oldnoelements = data->noelements;
8368
oldnoknots = data->noknots;
8369
8370
if(info) {
8371
printf("Creating additional %d elements and %d nodes.\n",nonewelements,nonewnodes);
8372
printf("Boundary layer mesh has %d elements and %d nodes.\n",noelements,noknots);
8373
}
8374
8375
/* there will be more nodes if the original mesh consists of triangles */
8376
if(maxelemtype <= 303)
8377
data->maxnodes = 4;
8378
else if(maxelemtype == 306)
8379
data->maxnodes = 8;
8380
8381
/* Allocate more space for the enlarged data set */
8382
newtopo = Imatrix(1,noelements,0,data->maxnodes-1);
8383
newmaterial = Ivector(1,noelements);
8384
newelementtypes = Ivector(1,noelements);
8385
newx = Rvector(1,noknots);
8386
newy = Rvector(1,noknots);
8387
newz = Rvector(1,noknots);
8388
for(i=1;i<=noknots;i++) newz[i] = 0.0;
8389
8390
elemwidth = Rvector(1,nonewelements);
8391
for(i=1;i<=nonewelements;i++) elemwidth[i] = 0.0;
8392
8393
herit = Ivector(1,noknots);
8394
for(i=1;i<=oldnoknots;i++) herit[i] = i;
8395
for(i=oldnoknots+1;i<=noknots;i++) herit[i] = 0;
8396
8397
8398
/* Set the old topology */
8399
for(j=1;j<=data->noelements;j++) {
8400
newmaterial[j] = data->material[j];
8401
newelementtypes[j] = data->elementtypes[j];
8402
for(i=0;i<data->elementtypes[j]%100;i++)
8403
newtopo[j][i] = data->topology[j][i];
8404
}
8405
8406
/* Set the old nodes */
8407
for(i=1;i<=data->noknots;i++) {
8408
newx[i] = data->x[i];
8409
newy[i] = data->y[i];
8410
}
8411
8412
topomap = Ivector(1,noknots);
8413
for(i=1;i<=noknots;i++) topomap[i] = i;
8414
8415
inside = Ivector(1,noelements);
8416
for(i=1;i<=noelements;i++) inside[i] = FALSE;
8417
8418
/* Set the new node topology and nodes */
8419
elemindx = data->noelements;
8420
for(j=0;j<MAXBOUNDARIES;j++) {
8421
if(!bound[j].created) continue;
8422
8423
for(i=1;i<=bound[j].nosides;i++) {
8424
8425
dolayer = FALSE;
8426
parent = bound[j].parent[i];
8427
parent2 = bound[j].parent2[i];
8428
use2 = FALSE;
8429
8430
for(k=0;k<nolayers;k++) {
8431
if(bound[j].types[i] == layerbounds[k]) {
8432
if(checkmaterials) {
8433
if(layerparents[k] < 0) continue;
8434
8435
if(data->material[parent] == layerparents[k]) {
8436
dolayer = k + 1;
8437
}
8438
else if(parent2) {
8439
l = parent;
8440
parent = parent2;
8441
parent2 = l;
8442
if(data->material[parent] == layerparents[k]) {
8443
use2 = TRUE;
8444
dolayer = k + 1;
8445
}
8446
}
8447
}
8448
else dolayer = k + 1;
8449
}
8450
}
8451
8452
8453
if(!dolayer) continue;
8454
8455
if(use2)
8456
GetElementSide(bound[j].parent2[i],bound[j].side2[i],bound[j].normal[i],
8457
data,ind,&sideelemtype);
8458
else
8459
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8460
data,ind,&sideelemtype);
8461
8462
inside[parent] = 1;
8463
8464
if(sideelemtype == 202)
8465
order = 1;
8466
else if(sideelemtype == 203)
8467
order = 2;
8468
8469
/* Check if some node should result into additional BC */
8470
for(i2=0;i2<sideelemtype%100;i2++) {
8471
sidebc[i2] = FALSE;
8472
if(i2 < 2 && layernode[ind[i2]] < 0) {
8473
layernode[ind[i2]] = abs(layernode[ind[i2]]);
8474
sidebc[i2] = TRUE;
8475
}
8476
}
8477
8478
/* Define the normal of the surface */
8479
dy = -(data->x[ind[1]] - data->x[ind[0]]);
8480
dx = data->y[ind[1]] - data->y[ind[0]];
8481
ds = sqrt(dx*dx+dy*dy);
8482
dx /= ds;
8483
dy /= ds;
8484
8485
n = layernumber[dolayer-1];
8486
ds = -layerthickness[dolayer-1];
8487
8488
for(l=0;l < n;l++) {
8489
elemindx++;
8490
8491
newmaterial[elemindx] = data->material[parent];
8492
inside[elemindx] = 1;
8493
8494
if(n <= 1 || fabs(layerratios[dolayer-1]-1.0) < 0.001) {
8495
q = (1.0*(l+1))/n;
8496
elemwidth[elemindx-oldnoelements] = ds / n;
8497
}
8498
else {
8499
ratio = pow(layerratios[dolayer-1],-1./(n-1.));
8500
q = (1.- pow(ratio,(Real)(l+1))) / (1.-pow(ratio,(Real)(n)));
8501
p = (1.- pow(ratio,(Real)(l))) / (1.-pow(ratio,(Real)(n)));
8502
elemwidth[elemindx-oldnoelements] = (q-p) * ds;
8503
}
8504
8505
8506
for(m=0;m<sideelemtype%100;m++) {
8507
8508
/* Make the possible additional BC appearing at side of the BL */
8509
if(sidebc[m]) {
8510
8511
bound[newbc].nosides += 1;
8512
i2 = bound[newbc].nosides;
8513
bound[newbc].parent[i2] = elemindx;
8514
bound[newbc].parent2[i2] = 0;
8515
bound[newbc].side[i2] = 3 - 2*m;
8516
bound[newbc].side2[i2] = 0;
8517
8518
for(i3=1;i3<=endbcs;i3++)
8519
if(ind[m] == endparents[i3]) {
8520
bound[newbc].types[i2] = endtypes[i3];
8521
endneighbours[2*i3-1] = layernode[ind[m]] + 1;
8522
break;
8523
}
8524
}
8525
8526
/* Set the node coordinates */
8527
if(m < 2) {
8528
nodeindx = layernode[ind[m]] + order*(l+1);
8529
}
8530
else {
8531
nodeindx = layernode[ind[m]] + (1+midpoints)*(l+1);
8532
}
8533
e1x = dx * q * ds;
8534
e1y = dy * q * ds;
8535
8536
/* Compute the normal of a joined node */
8537
if(herit[nodeindx] != 0) {
8538
8539
e2x = newx[nodeindx] - data->x[ind[m]];
8540
e2y = newy[nodeindx] - data->y[ind[m]];
8541
8542
p = (e1x*e2x + e1y*e2y)/(sqrt(e1x*e1x+e1y*e1y)*sqrt(e2x*e2x+e2y*e2y));
8543
8544
newx[nodeindx] += e1x - p * e2x;
8545
newy[nodeindx] += e1y - p * e2y;
8546
}
8547
else {
8548
herit[nodeindx] = ind[m];
8549
newx[nodeindx] = data->x[ind[m]] + e1x;
8550
newy[nodeindx] = data->y[ind[m]] + e1y;
8551
}
8552
}
8553
8554
/* Create the bulk elements */
8555
if(l==0) {
8556
newtopo[elemindx][3] = ind[0];
8557
newtopo[elemindx][2] = ind[1];
8558
if(order == 2) newtopo[elemindx][6] = ind[2];
8559
}
8560
else {
8561
newtopo[elemindx][3] = layernode[ind[0]] + order*l;
8562
newtopo[elemindx][2] = layernode[ind[1]] + order*l;
8563
if(order == 2) newtopo[elemindx][6] = layernode[ind[2]] + (midpoints+1)*l;
8564
}
8565
newtopo[elemindx][0] = layernode[ind[0]] + order*(l+1);
8566
newtopo[elemindx][1] = layernode[ind[1]] + order*(l+1);
8567
8568
if(order == 2) {
8569
newtopo[elemindx][7] = layernode[ind[0]] + order*l+1;
8570
newtopo[elemindx][5] = layernode[ind[1]] + order*l+1;
8571
newtopo[elemindx][4] = layernode[ind[2]] + (midpoints+1)*(l+1);
8572
if(midpoints) newtopo[elemindx][8] = layernode[ind[2]] + 2*l+1;
8573
}
8574
8575
if(order == 1) {
8576
newelementtypes[elemindx] = 404;
8577
}
8578
else if(midpoints) {
8579
newelementtypes[elemindx] = 409;
8580
}
8581
else {
8582
newelementtypes[elemindx] = 408;
8583
}
8584
8585
8586
if(l == n-1 && parent2) {
8587
8588
elemtype = data->elementtypes[parent2];
8589
inside[parent2] = 2;
8590
8591
for(i2=0;i2<elemtype%100;i2++) {
8592
for(i3=0;i3<sideelemtype%100;i3++) {
8593
if(data->topology[parent2][i2] == ind[i3]) {
8594
if(i3 < 2) {
8595
topomap[ind[i3]] = layernode[ind[i3]] + order * n;
8596
}
8597
else {
8598
topomap[ind[i3]] = layernode[ind[i3]] + (midpoints+1) * n;
8599
}
8600
}
8601
}
8602
}
8603
}
8604
}
8605
8606
/* Finally set the BC to point to the new boundary */
8607
if(use2) {
8608
bound[j].side2[i] = 0;
8609
bound[j].parent2[i] = elemindx;
8610
}
8611
else {
8612
bound[j].side[i] = 0;
8613
bound[j].parent[i] = elemindx;
8614
}
8615
}
8616
}
8617
8618
8619
{
8620
int *inside2;
8621
inside2 = Ivector(1,noknots);
8622
for(i=1;i<=noknots;i++) inside2[i] = 0;
8623
8624
/* Put a marker to all nodes that belong to elements that are on the outside */
8625
for(j=1;j<=noelements;j++) {
8626
if(inside[j] == 2) {
8627
elemtype = data->elementtypes[j];
8628
for(i=0;i<elemtype/100;i++) {
8629
inside2[newtopo[j][i]] = TRUE;
8630
}
8631
}
8632
}
8633
8634
/* Now check other outside elements that have at least 2 nodes that are also on outside */
8635
for(j=1;j<=noelements;j++) {
8636
if(!inside[j]) {
8637
elemtype = data->elementtypes[j];
8638
k = 0;
8639
for(i=0;i<elemtype/100;i++)
8640
if(inside2[newtopo[j][i]]) k++;
8641
if(k > 1) inside[j] = 2;
8642
}
8643
}
8644
free_Ivector(inside2,1,noknots);
8645
8646
/* Still, go through all elements and if they are not on the list of
8647
active materials assume them outside */
8648
if(checkmaterials) {
8649
for(j=1;j<=oldnoelements;j++) {
8650
dolayer = FALSE;
8651
for(k=0;k<nolayers;k++)
8652
if(data->material[j] == layerparents[k]) dolayer = TRUE;
8653
8654
if(!dolayer) {
8655
if(inside[j] == 1) printf("Element %d of material %d should be in the inside\n",
8656
j,data->material[j]);
8657
inside[j] = 2;
8658
}
8659
}
8660
}
8661
8662
/* And finally remap the nodes that are on the outside */
8663
for(j=1;j<=noelements;j++) {
8664
if(inside[j] == 2) {
8665
elemtype = data->elementtypes[j];
8666
for(i=0;i<elemtype%100;i++)
8667
newtopo[j][i] = topomap[data->topology[j][i]];
8668
}
8669
}
8670
}
8671
8672
8673
/* Put the pointers to the enlarged data set and destroy the old data */
8674
oldx = data->x;
8675
oldy = data->y;
8676
oldtopo = data->topology;
8677
8678
data->noelements = noelements;
8679
data->noknots = noknots;
8680
data->x = newx;
8681
data->y = newy;
8682
data->z = newz;
8683
8684
free_Ivector(data->elementtypes,1,oldnoelements);
8685
data->elementtypes = newelementtypes;
8686
8687
free_Ivector(data->material,1,oldnoelements);
8688
data->material = newmaterial;
8689
data->topology = newtopo;
8690
8691
8692
/* In case one wants to fit the mesh inside the original mesh
8693
the mesh nodes may be put to new positions using an appropriate filter. */
8694
8695
8696
/* For higher order elements remove the middlenodes from the list of cornernodes */
8697
if(maxelemtype%100 > 4) {
8698
if(info) printf("Marking the higher order nodes\n");
8699
8700
nonlin = Ivector(1,noknots);
8701
for(i=1;i<=noknots;i++) nonlin[i] = FALSE;
8702
8703
for(j=1;j<=noelements;j++) {
8704
elemtype = data->elementtypes[j];
8705
for(i=elemtype/100;i<elemtype%100;i++) {
8706
k = data->topology[j][i];
8707
nonlin[k] = TRUE;
8708
}
8709
}
8710
}
8711
8712
8713
if(maxfilters) {
8714
int method,iter;
8715
int ind1,ind2,ind3,*fixedx=NULL,*fixedy=NULL;
8716
Real *aidx=NULL,*aidy=NULL,*weights=NULL;
8717
Real maxerror=0.0,minds,dx2,dy2,ds2,fii;
8718
8719
/* There are three methods how to put the weight in the filter,
8720
1) 1/s, 2) fii/s, 3) sin(fii)/s, the second option seems to be best. */
8721
method = 2;
8722
8723
if(info) printf("Filtering the mesh to meet the original geometry\n");
8724
8725
fixedx = Ivector(1,noknots);
8726
fixedy = Ivector(1,noknots);
8727
weights = Rvector(1,noknots);
8728
aidx = Rvector(1,noknots);
8729
aidy = Rvector(1,noknots);
8730
8731
/* Set all the fixed boundaries */
8732
for(i=1;i<=noknots;i++) fixedx[i] = fixedy[i] = 0;
8733
8734
/* First, make all other materials except the ones with BL to be fixed */
8735
if(checkmaterials) {
8736
for(j=1;j<=noelements;j++) {
8737
8738
elemtype = data->elementtypes[j];
8739
dolayer = FALSE;
8740
for(k=0;k<nolayers;k++)
8741
if(data->material[j] == layerparents[k]) dolayer = TRUE;
8742
8743
for(i=0;i<elemtype/100;i++) {
8744
ind1 = data->topology[j][i];
8745
if(dolayer && fixedx[ind1]%2 == 0)
8746
fixedx[ind1] += 1;
8747
if(!dolayer && fixedx[ind1] < 2)
8748
fixedx[ind1] += 2;
8749
}
8750
}
8751
for(i=1;i<=noknots;i++) {
8752
if(fixedx[i] == 2)
8753
fixedy[i] = 2;
8754
else
8755
fixedx[i] = 0;
8756
}
8757
}
8758
8759
/* Then set all BC:s fixed except the tangential ones */
8760
for(j=0;j<MAXBOUNDARIES;j++) {
8761
if(!bound[j].created) continue;
8762
8763
for(i=1;i<=bound[j].nosides;i++) {
8764
8765
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8766
data,ind,&sideelemtype);
8767
8768
dx = fabs(newx[ind[0]] - newx[ind[1]]);
8769
dy = fabs(newy[ind[0]] - newy[ind[1]]);
8770
if(dx > rectfactor * dy) {
8771
for(l=0;l<sideelemtype%100;l++) {
8772
fixedy[ind[l]] = TRUE;
8773
}
8774
}
8775
else if(dy > rectfactor * dx) {
8776
for(l=0;l<sideelemtype%100;l++) {
8777
fixedx[ind[l]] = TRUE;
8778
}
8779
}
8780
else {
8781
for(l=0;l<sideelemtype%100;l++) {
8782
fixedy[ind[l]] = TRUE;
8783
fixedx[ind[l]] = TRUE;
8784
}
8785
}
8786
}
8787
}
8788
8789
8790
/* Then set possibly all remaining active boundaries to be fixed */
8791
for(j=0;j<MAXBOUNDARIES;j++) {
8792
if(!bound[j].created) continue;
8793
8794
for(i=1;i<=bound[j].nosides;i++) {
8795
8796
dolayer = FALSE;
8797
parent = bound[j].parent[i];
8798
parent2 = bound[j].parent2[i];
8799
use2 = FALSE;
8800
8801
GetElementSide(bound[j].parent[i],bound[j].side[i],bound[j].normal[i],
8802
data,ind,&sideelemtype);
8803
8804
for(k=0;k<nolayers;k++) {
8805
if(bound[j].types[i] == layerbounds[k]) {
8806
if(checkmaterials) {
8807
if(layerparents[k] < 0) continue;
8808
8809
if(data->material[parent] == layerparents[k]) {
8810
dolayer = k + 1;
8811
}
8812
else if(parent2) {
8813
l = parent;
8814
parent = parent2;
8815
parent2 = l;
8816
if(data->material[parent] == layerparents[k]) {
8817
use2 = TRUE;
8818
dolayer = k + 1;
8819
}
8820
}
8821
}
8822
else dolayer = k + 1;
8823
}
8824
}
8825
8826
if(dolayer) {
8827
for(l=0;l<sideelemtype%100;l++) {
8828
fixedy[ind[l]] = TRUE;
8829
fixedx[ind[l]] = TRUE;
8830
}
8831
}
8832
}
8833
}
8834
8835
/* Finally loose the problematic triple nodes */
8836
for(j=1;j<=endbcs;j++) {
8837
k = endnodes[j];
8838
if(k) {
8839
fixedx[k] = FALSE;
8840
fixedy[k] = FALSE;
8841
}
8842
8843
/* for second order elements */
8844
k = endnodes2[j];
8845
if(k) {
8846
fixedx[k] = FALSE;
8847
fixedy[k] = FALSE;
8848
}
8849
}
8850
8851
8852
j = 0;
8853
for(i=1;i<=noknots;i++) if(fixedx[i]) j += 1;
8854
if(info) printf("Number of fixed nodes in x-direction is %d\n",j);
8855
8856
j = 0;
8857
for(i=1;i<=noknots;i++) if(fixedy[i]) j += 1;
8858
if(info) printf("Number of fixed nodes in y-direction is %d\n",j);
8859
8860
for(j=1;j<=noknots;j++) {
8861
8862
if(fixedx[j]) {
8863
if(j <= oldnoknots)
8864
newx[j] = aidx[j] = oldx[j];
8865
else
8866
newx[j] = aidx[j] = oldx[herit[j]];
8867
}
8868
if(fixedy[j]) {
8869
if(j <= oldnoknots)
8870
newy[j] = aidy[j] = oldy[j];
8871
else
8872
newy[j] = aidy[j] = oldy[herit[j]];
8873
}
8874
}
8875
8876
8877
for(iter=1;iter<=maxfilters;iter++) {
8878
maxerror = 0.0;
8879
minds = 1.0e10;
8880
8881
for(j=1;j<=noknots;j++) {
8882
8883
weights[j] = 0.0;
8884
8885
if(!fixedx[j]) {
8886
aidx[j] = newx[j];
8887
newx[j] = 0.0;
8888
}
8889
if(!fixedy[j]) {
8890
aidy[j] = newy[j];
8891
newy[j] = 0.0;
8892
}
8893
}
8894
8895
for(j=1;j<=noelements;j++) {
8896
elemtype = data->elementtypes[j];
8897
nonodes = elemtype / 100;
8898
8899
for(i=0;i<nonodes;i++) {
8900
8901
i2 = (i+1)%nonodes;
8902
i3 = (i+2)%nonodes;
8903
8904
ind1 = data->topology[j][i];
8905
ind2 = data->topology[j][i2];
8906
ind3 = data->topology[j][i3];
8907
8908
if(j<=oldnoelements) {
8909
dx = oldx[oldtopo[j][i2]] - oldx[oldtopo[j][i]];
8910
dy = oldy[oldtopo[j][i2]] - oldy[oldtopo[j][i]];
8911
ds = sqrt(dx*dx+dy*dy);
8912
}
8913
else {
8914
ds = fabs(elemwidth[j-oldnoelements]);
8915
}
8916
if(ds < minds) minds = ds;
8917
8918
8919
if(j<=oldnoelements) {
8920
dx2 = oldx[oldtopo[j][i2]] - oldx[oldtopo[j][i3]];
8921
dy2 = oldy[oldtopo[j][i2]] - oldy[oldtopo[j][i3]];
8922
ds2 = sqrt(dx2*dx2+dy2*dy2);
8923
}
8924
else {
8925
ds2 = fabs(elemwidth[j-oldnoelements]);
8926
}
8927
8928
if(j <= oldnoelements && ds * ds2 < 1.0e-50) {
8929
printf("problem elem %d and nodes %d (%d %d)\n",j,i2,i,i3);
8930
printf("dist ds=%.3e ds2=%.3e\n",ds,ds2);
8931
printf("coord: %.3e %.3e\n",oldx[oldtopo[j][i2]], oldy[oldtopo[j][i2]]);
8932
continue;
8933
}
8934
8935
if(abs(method) == 2 && j<=oldnoelements) {
8936
fii = acos((dx*dx2+dy*dy2)/(ds*ds2)) / (FM_PI/2.0);
8937
}
8938
else if(abs(method) == 3 && j<=oldnoelements) {
8939
fii = acos((dx*dx2+dy*dy2)/(ds*ds2));
8940
fii = sin(fii);
8941
}
8942
else {
8943
fii = 1.0;
8944
}
8945
8946
8947
/* Eliminate the very difficult triple nodes */
8948
dolayer = FALSE;
8949
for(k=1;k<=endbcs;k++)
8950
if(ind2 == endnodes[k]) dolayer = k;
8951
8952
if(dolayer) {
8953
for(k=1;k<=2;k++) {
8954
if(endneighbours[2*(dolayer-1)+k] == ind1) {
8955
weights[ind2] += fii / ds;
8956
if(!fixedx[ind2]) newx[ind2] += aidx[ind1] * fii / ds;
8957
if(!fixedy[ind2]) newy[ind2] += aidy[ind1] * fii / ds;
8958
}
8959
}
8960
for(k=1;k<=2;k++) {
8961
if(endneighbours[2*(dolayer-1)+k] == ind3) {
8962
weights[ind2] += fii / ds2;
8963
if(!fixedx[ind2]) newx[ind2] += aidx[ind3] * fii / ds2;
8964
if(!fixedy[ind2]) newy[ind2] += aidy[ind3] * fii / ds2;
8965
}
8966
}
8967
}
8968
else {
8969
if(ind2 <= oldnoknots || herit[ind1] == herit[ind2]) {
8970
weights[ind2] += fii / ds;
8971
if(!fixedx[ind2]) newx[ind2] += aidx[ind1] * fii / ds;
8972
if(!fixedy[ind2]) newy[ind2] += aidy[ind1] * fii / ds;
8973
}
8974
8975
if(ind2 <= oldnoknots || herit[ind3] == herit[ind2]) {
8976
weights[ind2] += fii / ds2;
8977
if(!fixedx[ind2]) newx[ind2] += aidx[ind3] * fii / ds2;
8978
if(!fixedy[ind2]) newy[ind2] += aidy[ind3] * fii / ds2;
8979
}
8980
}
8981
}
8982
}
8983
8984
if(maxelemtype%100 > 4) {
8985
for(j=1;j<=noknots;j++) {
8986
if(nonlin[j]) continue;
8987
8988
if(weights[j] > 1.0e-50) {
8989
if(!fixedx[j]) newx[j] /= weights[j];
8990
if(!fixedy[j]) newy[j] /= weights[j];
8991
}
8992
else if(iter==1) {
8993
printf("no weight for index %d\n",j);
8994
}
8995
8996
dx = newx[j] - aidx[j];
8997
dy = newy[j] - aidy[j];
8998
8999
ds = dx*dx + dy*dy;
9000
if(ds > maxerror) maxerror = ds;
9001
}
9002
}
9003
else {
9004
for(j=1;j<=noknots;j++) {
9005
if(!fixedx[j]) newx[j] /= weights[j];
9006
if(!fixedy[j]) newy[j] /= weights[j];
9007
9008
dx = newx[j]-aidx[j];
9009
dy = newy[j]-aidy[j];
9010
9011
ds = dx*dx + dy*dy;
9012
if(ds > maxerror) maxerror = ds;
9013
}
9014
}
9015
9016
maxerror = sqrt(maxerror) / minds;
9017
if(maxerror < layereps) break;
9018
}
9019
9020
if(info) {
9021
printf("Filtered the new node coordinates %d times with final error %.3e.\n",
9022
iter-1,maxerror);
9023
}
9024
9025
/* In higher order elements map the middle nodes so that they lie in between
9026
the corner nodes */
9027
9028
9029
if(maxelemtype%100 > 4) {
9030
for(j=1;j<=noelements;j++) {
9031
elemtype = data->elementtypes[j];
9032
if(elemtype%100 <= elemtype/100) continue;
9033
9034
if(elemtype == 306) {
9035
for(k=0;k<3;k++) {
9036
if(!fixedx[newtopo[j][k+3]]) {
9037
newx[newtopo[j][k+3]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%3]]);
9038
}
9039
if(!fixedy[newtopo[j][k+3]]) {
9040
newy[newtopo[j][k+3]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%3]]);
9041
}
9042
}
9043
}
9044
9045
else if(elemtype == 408 || elemtype == 409) {
9046
9047
if(elemtype == 409) {
9048
newx[newtopo[j][8]] = 0.0;
9049
newy[newtopo[j][8]] = 0.0;
9050
}
9051
9052
for(k=0;k<4;k++) {
9053
if(!fixedx[newtopo[j][k+4]]) {
9054
newx[newtopo[j][k+4]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%4]]);
9055
}
9056
if(!fixedy[newtopo[j][k+4]]) {
9057
newy[newtopo[j][k+4]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%4]]);
9058
}
9059
if(elemtype == 409) {
9060
newx[newtopo[j][8]] += 0.25 * newx[newtopo[j][k]];
9061
newy[newtopo[j][8]] += 0.25 * newy[newtopo[j][k]];
9062
}
9063
}
9064
}
9065
else {
9066
printf("Unknown elementtype %d\n",elemtype);
9067
}
9068
}
9069
}
9070
9071
free_Ivector(fixedx,1,noknots);
9072
free_Ivector(fixedy,1,noknots);
9073
9074
free_Rvector(aidx,1,noknots);
9075
free_Rvector(aidy,1,noknots);
9076
free_Rvector(weights,1,noknots);
9077
}
9078
9079
if(bound[newbc].nosides > 0)
9080
bound[newbc].created = TRUE;
9081
9082
9083
/* In higher order elements map the middle nodes so that they lie in between
9084
the corner nodes. Elemtypes must be 408 or 409 since they are created in this
9085
subroutine */
9086
9087
if(!maxfilters && maxelemtype%100 > 4) {
9088
if(info) printf("Making the higher order nodes to lie in between\n");
9089
9090
for(j=oldnoelements+1;j<=noelements;j++) {
9091
9092
elemtype = data->elementtypes[j];
9093
if(elemtype%100 <= elemtype/100) continue;
9094
9095
if(elemtype == 408 || elemtype == 409) {
9096
9097
if(elemtype == 409) {
9098
newx[newtopo[j][8]] = 0.0;
9099
newy[newtopo[j][8]] = 0.0;
9100
}
9101
9102
for(k=0;k<4;k++) {
9103
newx[newtopo[j][k+4]] = 0.5 * (newx[newtopo[j][k]] + newx[newtopo[j][(k+1)%4]]);
9104
newy[newtopo[j][k+4]] = 0.5 * (newy[newtopo[j][k]] + newy[newtopo[j][(k+1)%4]]);
9105
9106
if(elemtype == 409) {
9107
newx[newtopo[j][8]] += 0.25 * newx[newtopo[j][k]];
9108
newy[newtopo[j][8]] += 0.25 * newy[newtopo[j][k]];
9109
}
9110
}
9111
}
9112
}
9113
}
9114
9115
9116
#if 0
9117
ReorderElements(data,bound,FALSE,corder,info);
9118
#endif
9119
9120
free_Imatrix(oldtopo,1,oldnoelements,0,oldmaxnodes-1);
9121
free_Ivector(layernode,1,oldnoknots);
9122
free_Rvector(oldx,1,oldnoknots);
9123
free_Rvector(oldy,1,oldnoknots);
9124
9125
if(info) printf("Boundary layers created successfully.\n");
9126
9127
if(checkmaterials && !second) {
9128
for(k=0;k<nolayers;k++) {
9129
if(layerparents[k] < 0) second = TRUE;
9130
layerparents[k] = -layerparents[k];
9131
}
9132
if(second) {
9133
if(info) printf("\nPerforming boundary layer generation again for negative materials\n");
9134
goto omstart;
9135
}
9136
}
9137
9138
return(0);
9139
}
9140
9141
9142
9143
9144
9145
int CreateBoundaryLayerDivide(struct FemType *data,struct BoundaryType *bound,
9146
int nolayers, int *layerbounds, int *layernumber,
9147
Real *layerratios, Real *layerthickness, int *layerparents,
9148
int info)
9149
/* Create Boundary layers that may be used to solve accurately fluid
9150
flow problems and similar equations. In this subroutine the boundary layer
9151
is created by dividing the elements close to boundary. */
9152
{
9153
int i,j,k,l,dim,maxbc,maxelemtype,dolayer,parent,nlayer,sideelemtype,elemind,side;
9154
int noelements,noknots,oldnoknots,oldnoelements,oldmaxnodes,nonewnodes,nonewelements;
9155
int maxcon,elemsides,elemdone,midpoints,order,bcnodes,elemhits,elemtype,goforit;
9156
int ind[MAXNODESD2],baseind[2],topnode[2],basenode[2];
9157
int *layernode=NULL,*newelementtypes=NULL,**newtopo=NULL,**oldtopo=NULL;
9158
int *newmaterial=NULL,**edgepairs=NULL,*sharednode=NULL;
9159
Real dx[2],dy[2],x0[2],y0[2];
9160
Real *newx=NULL,*newy=NULL,*newz=NULL,*oldx=NULL,*oldy=NULL,*oldz=NULL;
9161
Real slayer,qlayer,ratio,q;
9162
9163
9164
dim = data->dim;
9165
maxelemtype = GetMaxElementType(data);
9166
9167
if(maxelemtype > 409) {
9168
printf("Subroutine implemented only up to 2nd degree!\n");
9169
return(2);
9170
}
9171
9172
if(info) printf("Largest elementtype is %d\n",maxelemtype);
9173
9174
9175
oldnoelements = noelements = data->noelements;
9176
oldnoknots = noknots = data->noknots;
9177
oldmaxnodes = data->maxnodes;
9178
9179
layernode = Ivector(1,oldnoknots);
9180
for(i=1;i<=oldnoknots;i++)
9181
layernode[i] = 0;
9182
9183
sharednode = Ivector(1,oldnoknots);
9184
for(i=1;i<=oldnoknots;i++)
9185
sharednode[i] = 0;
9186
9187
9188
/* Go through all the boundaries with boundary layer definitions and compute
9189
the number of nodes at the surface. */
9190
9191
maxbc = 0;
9192
qlayer = 0.0;
9193
slayer = 0.0;
9194
nlayer = 0;
9195
9196
/* Go through the layers and check which ones are active */
9197
for(j=0;j<MAXBOUNDARIES;j++) {
9198
if(!bound[j].created) continue;
9199
9200
for(i=1;i<=bound[j].nosides;i++) {
9201
dolayer = FALSE;
9202
parent = bound[j].parent[i];
9203
if(bound[j].types[i] > maxbc) maxbc = bound[j].types[i];
9204
9205
for(k=0;k<nolayers;k++) {
9206
if(bound[j].types[i] == layerbounds[k]) {
9207
nlayer = layernumber[k];
9208
slayer = layerthickness[k];
9209
qlayer = layerratios[k];
9210
dolayer = TRUE;
9211
}
9212
}
9213
if(!dolayer) continue;
9214
9215
/* We have found an active boundary layer */
9216
GetElementSide(parent,bound[j].side[i],bound[j].normal[i],
9217
data,ind,&sideelemtype);
9218
9219
midpoints = FALSE;
9220
if(sideelemtype == 202) {
9221
order = 1;
9222
}
9223
else if(sideelemtype == 203) {
9224
order = 2;
9225
if(maxelemtype > 408) midpoints = TRUE;
9226
}
9227
9228
for(l=0;l<sideelemtype%100;l++)
9229
layernode[ind[l]] += 1;
9230
}
9231
}
9232
9233
if(slayer > 1.0 || slayer < 1.0e-20)
9234
slayer = 1.0;
9235
9236
bcnodes = 0;
9237
maxcon = 0;
9238
for(i=1;i<=data->noknots;i++) {
9239
if(layernode[i]) bcnodes++;
9240
maxcon = MAX(maxcon, layernode[i]);
9241
}
9242
9243
if(info) printf("Found %d new nodes in the boundary layers!\n",bcnodes);
9244
if(!bcnodes) return(0);
9245
if(info) printf("There are %d connections at maximum\n",maxcon);
9246
9247
/* there will be more nodes if the original mesh consists of triangles */
9248
if(maxelemtype <= 303)
9249
data->maxnodes = 4;
9250
else if(maxelemtype == 306)
9251
data->maxnodes = 8;
9252
9253
/* Compute the number of new elements */
9254
nonewelements = 0;
9255
for(j=1;j<=data->noelements;j++) {
9256
elemhits = 0;
9257
elemtype = data->elementtypes[j];
9258
for(i=0;i<elemtype%100;i++) {
9259
k = data->topology[j][i];
9260
if( layernode[k]) {
9261
sharednode[k] += 1;
9262
elemhits++;
9263
}
9264
}
9265
if(elemhits) {
9266
nonewelements += nlayer ;
9267
if(elemhits != 2) nonewelements += nlayer + 1;
9268
}
9269
}
9270
printf("There will %d new elements\n",nonewelements);
9271
9272
/* This is a conservative estimate */
9273
nonewnodes = 2*nonewelements;
9274
9275
edgepairs = Imatrix(1,nonewnodes,1,3);
9276
for(j=1;j<=nonewnodes;j++)
9277
edgepairs[j][1] = edgepairs[j][2] = edgepairs[j][3] = 0;
9278
9279
9280
/* The size of new mesh */
9281
oldnoelements = data->noelements;
9282
oldnoknots = data->noknots;
9283
oldtopo = data->topology;
9284
oldx = data->x;
9285
oldy = data->y;
9286
oldz = data->z;
9287
9288
noknots = oldnoknots + nonewnodes;
9289
noelements = oldnoelements + nonewelements;
9290
9291
if(info) {
9292
printf("Creating additional %d elements and %d nodes.\n",nonewelements,nonewnodes);
9293
printf("Boundary layer mesh has at maximum %d elements and %d nodes.\n",noelements,noknots);
9294
}
9295
9296
/* Allocate more space for the enlarged data set */
9297
newtopo = Imatrix(1,noelements,0,data->maxnodes-1);
9298
newmaterial = Ivector(1,noelements);
9299
newelementtypes = Ivector(1,noelements);
9300
newx = Rvector(1,noknots);
9301
newy = Rvector(1,noknots);
9302
newz = Rvector(1,noknots);
9303
9304
/* Set the old topology */
9305
for(j=1;j<=data->noelements;j++) {
9306
newmaterial[j] = data->material[j];
9307
newelementtypes[j] = data->elementtypes[j];
9308
for(i=0;i<data->elementtypes[j]%100;i++)
9309
newtopo[j][i] = data->topology[j][i];
9310
}
9311
9312
/* Set the old nodes */
9313
for(i=1;i<=data->noknots;i++) {
9314
newx[i] = data->x[i];
9315
newy[i] = data->y[i];
9316
newz[i] = data->z[i];
9317
}
9318
9319
noelements = data->noelements;
9320
elemind = noelements;
9321
noknots = data->noknots;
9322
9323
/* Go through elements and make the new elements and nodes */
9324
for(j=1;j<=data->noelements;j++) {
9325
elemhits = 0;
9326
elemtype = data->elementtypes[j];
9327
elemsides = elemtype % 100;
9328
for(i=0;i<elemsides;i++)
9329
if( layernode[ data->topology[j][i] ]) elemhits++;
9330
if(!elemhits) continue;
9331
9332
if(elemtype == 404) {
9333
elemdone = FALSE;
9334
9335
for(side=0;side<elemsides;side++) {
9336
9337
goforit = FALSE;
9338
if(elemhits == 2 || elemhits == 3)
9339
if(layernode[oldtopo[j][side]] && layernode[oldtopo[j][(side+1)%elemsides]]) goforit = TRUE;
9340
if(elemhits == 1)
9341
if(layernode[oldtopo[j][side]]) goforit = TRUE;
9342
if(!goforit) continue;
9343
9344
/* Treat the special case of three hits
9345
In case of corners find the single node that is not on the boundary */
9346
if(elemhits == 3) {
9347
for(k=0;k<4;k++)
9348
if(!layernode[oldtopo[j][k]]) break;
9349
if(0) printf("Special node %d in corner %d\n",oldtopo[j][k],k);
9350
9351
basenode[0] = oldtopo[j][side];
9352
basenode[1] = oldtopo[j][(side+1)%elemsides];
9353
topnode[0] = oldtopo[j][k];
9354
topnode[1] = oldtopo[j][k];
9355
}
9356
else if(elemhits == 2) {
9357
basenode[0] = oldtopo[j][side];
9358
basenode[1] = oldtopo[j][(side+1)%elemsides];
9359
topnode[0] = oldtopo[j][(side+3)%elemsides];
9360
topnode[1] = oldtopo[j][(side+2)%elemsides];
9361
}
9362
else if(elemhits == 1) {
9363
basenode[0] = oldtopo[j][side];
9364
basenode[1] = basenode[0];
9365
topnode[0] = oldtopo[j][(side+3)%elemsides];
9366
topnode[1] = oldtopo[j][(side+1)%elemsides];
9367
}
9368
9369
for(k=0;k<=1;k++) {
9370
for(i=1;i<=nonewnodes;i++) {
9371
if(!edgepairs[i][1]) break;
9372
if(basenode[k] == edgepairs[i][1] && topnode[k] == edgepairs[i][2]) break;
9373
}
9374
if(!edgepairs[i][1]) {
9375
edgepairs[i][1] = basenode[k];
9376
edgepairs[i][2] = topnode[k];
9377
baseind[k] = noknots;
9378
edgepairs[i][3] = baseind[k];
9379
noknots += nlayer;
9380
}
9381
else {
9382
if(0) printf("Using existing nodes\n");
9383
baseind[k] = edgepairs[i][3];
9384
}
9385
x0[k] = oldx[basenode[k]];
9386
y0[k] = oldy[basenode[k]];
9387
dx[k] = oldx[topnode[k]] - x0[k];
9388
dy[k] = oldy[topnode[k]] - y0[k];
9389
9390
for(i=1;i<=nlayer;i++) {
9391
if(nlayer <= 1 || fabs(qlayer-1.0) < 0.001) {
9392
q = (1.0*i) / (nlayer+1);
9393
}
9394
else {
9395
ratio = pow(qlayer,1.0/nlayer);
9396
q = (1.- pow(ratio,1.0*i)) / (1.- pow(ratio,1.0+nlayer));
9397
}
9398
q *= slayer;
9399
newx[baseind[k]+i] = x0[k] + q * dx[k];
9400
newy[baseind[k]+i] = y0[k] + q * dy[k];
9401
}
9402
}
9403
9404
/* 0:th element */
9405
if(elemhits == 1) {
9406
newelementtypes[j] = 303;
9407
newtopo[j][0] = basenode[0];
9408
newtopo[j][1] = baseind[1] + 1;
9409
newtopo[j][2] = baseind[0] + 1;
9410
}
9411
else if(elemhits == 3 && elemdone) {
9412
elemind++;
9413
newelementtypes[elemind] = 404;
9414
newmaterial[elemind] = newmaterial[j];
9415
newtopo[elemind][side] = basenode[0];
9416
newtopo[elemind][(side+1)%elemsides] = basenode[1];
9417
newtopo[elemind][(side+2)%elemsides] = baseind[1] + 1;
9418
newtopo[elemind][(side+3)%elemsides] = baseind[0] + 1;
9419
}
9420
else {
9421
newtopo[j][(side+2)%elemsides] = baseind[1] + 1;
9422
newtopo[j][(side+3)%elemsides] = baseind[0] + 1;
9423
}
9424
9425
for(i=1;i<nlayer;i++) {
9426
elemind++;
9427
newelementtypes[elemind] = 404;
9428
newmaterial[elemind] = newmaterial[j];
9429
newtopo[elemind][0] = baseind[0] + i;
9430
newtopo[elemind][1] = baseind[1] + i;
9431
newtopo[elemind][2] = baseind[1] + i+1;
9432
newtopo[elemind][3] = baseind[0] + i+1;
9433
}
9434
9435
/* n:th element */
9436
if(elemhits == 3) {
9437
elemind++;
9438
newelementtypes[elemind] = 303;
9439
newmaterial[elemind] = newmaterial[j];
9440
newtopo[elemind][0] = baseind[0] + nlayer;
9441
newtopo[elemind][1] = baseind[1] + nlayer;
9442
newtopo[elemind][2] = topnode[0];
9443
}
9444
else if(elemhits == 2 || elemhits == 1) {
9445
elemind++;
9446
newelementtypes[elemind] = 404;
9447
newmaterial[elemind] = newmaterial[j];
9448
newtopo[elemind][0] = baseind[0] + nlayer;
9449
newtopo[elemind][1] = baseind[1] + nlayer;
9450
newtopo[elemind][2] = topnode[1];
9451
newtopo[elemind][3] = topnode[0];
9452
}
9453
/* n+1:th element */
9454
if(elemhits == 1) {
9455
elemind++;
9456
newelementtypes[elemind] = 303;
9457
newmaterial[elemind] = newmaterial[j];
9458
newtopo[elemind][0] = topnode[1];
9459
newtopo[elemind][1] = oldtopo[j][(side+2)%elemsides];
9460
newtopo[elemind][2] = topnode[0];
9461
}
9462
9463
elemdone = TRUE;
9464
}
9465
if(!elemdone)
9466
printf("cannot handle quadrilaterals with %d hits\n",elemhits);
9467
}
9468
9469
9470
else if(elemtype == 303) {
9471
elemdone = FALSE;
9472
9473
for(side=0;side<elemsides;side++) {
9474
9475
goforit = FALSE;
9476
if(elemhits == 2) {
9477
if(layernode[oldtopo[j][side]] && layernode[oldtopo[j][(side+1)%elemsides]]) goforit = TRUE;
9478
}
9479
else if(elemhits == 1) {
9480
if(layernode[oldtopo[j][side]]) goforit = TRUE;
9481
}
9482
else if(elemhits == 3) {
9483
if(sharednode[oldtopo[j][side]] == 1) goforit = TRUE;
9484
9485
printf("The boundary layer creation for certain corner triangles is omitted\n");
9486
goforit = FALSE;
9487
}
9488
if(!goforit) continue;
9489
9490
if(elemhits == 3) {
9491
if(1) printf("Special node %d in corner %d\n",oldtopo[j][side],side);
9492
basenode[0] = oldtopo[j][side];
9493
basenode[1] = basenode[0];
9494
topnode[0] = oldtopo[j][(side+2)%elemsides];
9495
topnode[1] = oldtopo[j][(side+1)%elemsides];
9496
}
9497
else if(elemhits == 2) {
9498
basenode[0] = oldtopo[j][side];
9499
basenode[1] = oldtopo[j][(side+1)%elemsides];
9500
topnode[0] = oldtopo[j][(side+2)%elemsides];
9501
topnode[1] = topnode[0];
9502
}
9503
else if(elemhits == 1) {
9504
basenode[0] = oldtopo[j][side];
9505
basenode[1] = basenode[0];
9506
topnode[0] = oldtopo[j][(side+2)%elemsides];
9507
topnode[1] = oldtopo[j][(side+1)%elemsides];
9508
}
9509
9510
for(k=0;k<=1;k++) {
9511
for(i=1;i<=nonewnodes;i++) {
9512
if(!edgepairs[i][1]) break;
9513
if(basenode[k] == edgepairs[i][1] && topnode[k] == edgepairs[i][2]) break;
9514
}
9515
if(!edgepairs[i][1]) {
9516
edgepairs[i][1] = basenode[k];
9517
edgepairs[i][2] = topnode[k];
9518
baseind[k] = noknots;
9519
edgepairs[i][3] = baseind[k];
9520
noknots += nlayer;
9521
}
9522
else {
9523
if(0) printf("Using existing nodes\n");
9524
baseind[k] = edgepairs[i][3];
9525
}
9526
9527
x0[k] = oldx[basenode[k]];
9528
y0[k] = oldy[basenode[k]];
9529
dx[k] = oldx[topnode[k]] - x0[k];
9530
dy[k] = oldy[topnode[k]] - y0[k];
9531
9532
for(i=1;i<=nlayer;i++) {
9533
if(nlayer <= 1 || fabs(qlayer-1.0) < 0.001) {
9534
q = (1.0*i) / (nlayer+1);
9535
}
9536
else {
9537
ratio = pow(qlayer,1.0/nlayer);
9538
q = (1.- pow(ratio,1.0*i)) / (1.- pow(ratio,1.0*nlayer));
9539
}
9540
q *= slayer;
9541
newx[baseind[k]+i] = x0[k] + q * dx[k];
9542
newy[baseind[k]+i] = y0[k] + q * dy[k];
9543
}
9544
}
9545
9546
/* 0:th element */
9547
if(elemhits == 1 || elemhits == 3) {
9548
newelementtypes[j] = 303;
9549
newtopo[j][0] = basenode[0];
9550
newtopo[j][1] = baseind[1] + 1;
9551
newtopo[j][2] = baseind[0] + 1;
9552
}
9553
else if(elemhits == 2) {
9554
newelementtypes[j] = 404;
9555
newtopo[j][side] = basenode[0];
9556
newtopo[j][(side+1)%4] = basenode[1];
9557
newtopo[j][(side+2)%4] = baseind[1] + 1;
9558
newtopo[j][(side+3)%4] = baseind[0] + 1;
9559
}
9560
9561
for(i=1;i<nlayer;i++) {
9562
elemind++;
9563
newelementtypes[elemind] = 404;
9564
newmaterial[elemind] = newmaterial[j];
9565
newtopo[elemind][0] = baseind[0] + i;
9566
newtopo[elemind][1] = baseind[1] + i;
9567
newtopo[elemind][2] = baseind[1] + i+1;
9568
newtopo[elemind][3] = baseind[0] + i+1;
9569
}
9570
9571
/* n:th element */
9572
if(elemhits == 1 || elemhits == 3) {
9573
elemind++;
9574
newelementtypes[elemind] = 404;
9575
newmaterial[elemind] = newmaterial[j];
9576
newtopo[elemind][0] = baseind[0] + nlayer;
9577
newtopo[elemind][1] = baseind[1] + nlayer;
9578
newtopo[elemind][2] = topnode[1];
9579
newtopo[elemind][3] = topnode[0];
9580
}
9581
else if(elemhits == 2) {
9582
elemind++;
9583
newelementtypes[elemind] = 303;
9584
newmaterial[elemind] = newmaterial[j];
9585
newtopo[elemind][0] = baseind[0] + nlayer;
9586
newtopo[elemind][1] = baseind[1] + nlayer;
9587
newtopo[elemind][2] = topnode[1];
9588
}
9589
elemdone = TRUE;
9590
}
9591
if(!elemdone)
9592
printf("cannot handle triangles with %d hits\n",elemhits);
9593
}
9594
9595
else {
9596
printf("Not implemented for element %d\n",elemtype);
9597
}
9598
}
9599
noelements = elemind;
9600
9601
data->x = newx;
9602
data->y = newy;
9603
data->topology = newtopo;
9604
data->material = newmaterial;
9605
data->elementtypes = newelementtypes;
9606
data->noknots = noknots;
9607
data->noelements = elemind;
9608
9609
printf("The created boundary layer mesh has at %d elements and %d nodes.\n",noelements,noknots);
9610
9611
return(0);
9612
}
9613
9614
9615
9616
int RotateTranslateScale(struct FemType *data,struct ElmergridType *eg,int info)
9617
{
9618
int i;
9619
Real x,y,z,xz,yz,yx,zx,zy,xy,cx,cy,cz;
9620
Real xmin, xmax, ymin, ymax, zmin, zmax;
9621
9622
if(eg->scale) {
9623
if(info) printf("Scaling mesh with vector [%.3lg %.3lg %.3lg]\n",
9624
eg->cscale[0],eg->cscale[1],eg->cscale[2]);
9625
for(i=1;i<=data->noknots;i++) {
9626
data->x[i] *= eg->cscale[0];
9627
data->y[i] *= eg->cscale[1];
9628
data->z[i] *= eg->cscale[2];
9629
}
9630
if(0) printf("Scaling of mesh finished.\n");
9631
}
9632
9633
if(eg->rotate) {
9634
if(info) printf("Rotating mesh with degrees [%.3lg %.3lg %.3lg]\n",
9635
eg->crotate[0],eg->crotate[1],eg->crotate[2]);
9636
cx = FM_PI * eg->crotate[0]/180.0;
9637
cy = FM_PI * eg->crotate[1]/180.0;
9638
cz = FM_PI * eg->crotate[2]/180.0;
9639
9640
for(i=1;i<=data->noknots;i++) {
9641
9642
x = data->x[i];
9643
y = data->y[i];
9644
z = data->z[i];
9645
9646
xz = x*cos(cz) + y*sin(cz);
9647
yz = -x*sin(cz) + y*cos(cz);
9648
9649
if( fabs(cx) > 1.0e-8 || fabs(cy) > 1.0e-8 ) {
9650
yx = yz*cos(cx) + z*sin(cx);
9651
zx = -yz*sin(cx) + z*cos(cx);
9652
9653
zy = zx*cos(cy) + xz*sin(cy);
9654
xy = -zx*sin(cy) + xz*cos(cy);
9655
9656
data->x[i] = xy;
9657
data->y[i] = yx;
9658
data->z[i] = zy;
9659
}
9660
else {
9661
data->x[i] = xz;
9662
data->y[i] = yz;
9663
}
9664
}
9665
if(0) printf("Rotation of mesh finished.\n");
9666
}
9667
9668
if(eg->translate) {
9669
if(info) printf("Translating the mesh with vector [%.3lg %.3lg %.3lg]\n",
9670
eg->ctranslate[0],eg->ctranslate[1],eg->ctranslate[2]);
9671
for(i=1;i<=data->noknots;i++) {
9672
data->x[i] += eg->ctranslate[0];
9673
data->y[i] += eg->ctranslate[1];
9674
data->z[i] += eg->ctranslate[2];
9675
}
9676
if(0) printf("Translation of mesh finished.\n");
9677
}
9678
9679
if(eg->center) {
9680
xmin = xmax = data->x[1];
9681
ymin = ymax = data->y[1];
9682
zmin = zmax = data->z[1];
9683
9684
for(i=1;i<=data->noknots;i++) {
9685
xmax = MAX( xmax, data->x[i] );
9686
xmin = MIN( xmin, data->x[i] );
9687
ymax = MAX( ymax, data->y[i] );
9688
ymin = MIN( ymin, data->y[i] );
9689
zmax = MAX( zmax, data->z[i] );
9690
zmin = MIN( zmin, data->z[i] );
9691
}
9692
cx = 0.5 * (xmin + xmax);
9693
cy = 0.5 * (ymin + ymax);
9694
cz = 0.5 * (zmin + zmax);
9695
9696
if(info) printf("Setting new center to %.3e %.3e %.3e\n",cx,cy,cz);
9697
9698
for(i=1;i<=data->noknots;i++) {
9699
data->x[i] -= cx;
9700
data->y[i] -= cy;
9701
data->z[i] -= cz;
9702
}
9703
}
9704
9705
return(0);
9706
}
9707
9708
9709
9710
int CreateNodalGraph(struct FemType *data,int full,int info)
9711
{
9712
int i,j,k,l,m,totcon,noelements, noknots,elemtype,nonodes,hit,ind,ind2;
9713
int maxcon,percon,edge;
9714
9715
printf("Creating a nodal graph of the finite element mesh\n");
9716
9717
if(data->nodalexists) {
9718
printf("The nodal graph already exists!\n");
9719
smallerror("Nodal graph not done");
9720
return(1);
9721
}
9722
9723
maxcon = 0;
9724
totcon = 0;
9725
percon = 0;
9726
noelements = data->noelements;
9727
noknots = data->noknots;
9728
9729
for(i=1;i<=noelements;i++) {
9730
elemtype = data->elementtypes[i];
9731
9732
/* This sets only the connections resulting from element edges */
9733
if(!full) {
9734
int inds[2];
9735
for(edge=0;;edge++) {
9736
if( !GetElementGraph(i,edge,data,&inds[0]) ) break;
9737
9738
ind = inds[0];
9739
ind2 = inds[1];
9740
9741
hit = FALSE;
9742
for(l=0;l<maxcon;l++) {
9743
if(data->nodalgraph[l][ind] == ind2) hit = TRUE;
9744
if(data->nodalgraph[l][ind] == 0) break;
9745
}
9746
if(!hit) {
9747
if(l >= maxcon) {
9748
data->nodalgraph[maxcon] = Ivector(1,noknots);
9749
for(m=1;m<=noknots;m++)
9750
data->nodalgraph[maxcon][m] = 0;
9751
maxcon++;
9752
}
9753
data->nodalgraph[l][ind] = ind2;
9754
totcon++;
9755
}
9756
9757
/* Make also so symmetric connection */
9758
for(l=0;l<maxcon;l++) {
9759
if(data->nodalgraph[l][ind2] == ind) hit = TRUE;
9760
if(data->nodalgraph[l][ind2] == 0) break;
9761
}
9762
if(!hit) {
9763
if(l >= maxcon) {
9764
data->nodalgraph[maxcon] = Ivector(1,noknots);
9765
for(m=1;m<=noknots;m++)
9766
data->nodalgraph[maxcon][m] = 0;
9767
maxcon++;
9768
}
9769
data->nodalgraph[l][ind2] = ind;
9770
totcon++;
9771
}
9772
}
9773
}
9774
9775
/* This sets all elemental connections */
9776
else {
9777
nonodes = data->elementtypes[i] % 100;
9778
for(j=0;j<nonodes;j++) {
9779
ind = data->topology[i][j];
9780
for(k=0;k<nonodes;k++) {
9781
ind2 = data->topology[i][k];
9782
if(ind == ind2) continue;
9783
9784
hit = FALSE;
9785
for(l=0;l<maxcon;l++) {
9786
if(data->nodalgraph[l][ind] == ind2) hit = TRUE;
9787
if(data->nodalgraph[l][ind] == 0) break;
9788
}
9789
if(!hit) {
9790
if(l >= maxcon) {
9791
data->nodalgraph[maxcon] = Ivector(1,noknots);
9792
for(m=1;m<=noknots;m++)
9793
data->nodalgraph[maxcon][m] = 0;
9794
maxcon++;
9795
}
9796
data->nodalgraph[l][ind] = ind2;
9797
totcon++;
9798
}
9799
}
9800
}
9801
}
9802
9803
}
9804
9805
/* This adds the periodic connections */
9806
if( data->periodicexist ) {
9807
for(ind=1;ind<=noknots;ind++) {
9808
ind2 = data->periodic[ind];
9809
if(ind == ind2) continue;
9810
9811
hit = FALSE;
9812
for(l=0;l<maxcon;l++) {
9813
if(data->nodalgraph[l][ind] == ind2) hit = TRUE;
9814
if(data->nodalgraph[l][ind] == 0) break;
9815
}
9816
if(!hit) {
9817
if(l >= maxcon) {
9818
data->nodalgraph[maxcon] = Ivector(1,noknots);
9819
for(m=1;m<=noknots;m++)
9820
data->nodalgraph[maxcon][m] = 0;
9821
maxcon++;
9822
}
9823
data->nodalgraph[l][ind] = ind2;
9824
totcon++;
9825
percon++;
9826
}
9827
}
9828
}
9829
9830
data->nodalmaxconnections = maxcon;
9831
data->nodalexists = TRUE;
9832
9833
if(info) {
9834
printf("There are at maximum %d connections in nodal graph.\n",maxcon);
9835
printf("There are at all in all %d connections in nodal graph.\n",totcon);
9836
if(percon) printf("There are %d periodic connections in nodal graph.\n",percon);
9837
}
9838
9839
return(0);
9840
}
9841
9842
9843
int DestroyNodalGraph(struct FemType *data,int info)
9844
{
9845
int i,maxcon, noknots;
9846
9847
if(!data->nodalexists) {
9848
printf("You tried to destroy a non-existing nodal graph\n");
9849
return(1);
9850
}
9851
9852
maxcon = data->nodalmaxconnections;
9853
noknots = data->noknots;
9854
9855
for(i=0;i<maxcon;i++)
9856
free_Ivector(data->nodalgraph[i],1,noknots);
9857
9858
data->nodalmaxconnections = 0;
9859
data->nodalexists = FALSE;
9860
9861
if(info) printf("The nodal graph was destroyed\n");
9862
return(0);
9863
}
9864
9865
9866
9867
int CreateInverseTopology(struct FemType *data,int info)
9868
{
9869
int i,j,k,l,m,noelements,noknots,elemtype,nonodes,ind;
9870
int *neededby,minneeded,maxneeded;
9871
int step,totcon;
9872
int *rows,*cols;
9873
struct CRSType *invtopo;
9874
9875
invtopo = &data->invtopo;
9876
if(invtopo->created) {
9877
if(0) printf("The inverse topology already exists!\n");
9878
return(0);
9879
}
9880
9881
printf("Creating an inverse topology of the finite element mesh\n");
9882
9883
noelements = data->noelements;
9884
noknots = data->noknots;
9885
9886
neededby = Ivector(1,noknots);
9887
totcon = 0;
9888
9889
for(step=1;step<=2;step++) {
9890
9891
for(i=1;i<=noknots;i++)
9892
neededby[i] = 0;
9893
9894
for(i=1;i<=noelements;i++) {
9895
elemtype = data->elementtypes[i];
9896
nonodes = data->elementtypes[i] % 100;
9897
9898
for(j=0;j<nonodes;j++) {
9899
ind = data->topology[i][j];
9900
9901
if( step == 1 ) {
9902
neededby[ind] += 1;
9903
totcon += 1;
9904
}
9905
else {
9906
k = rows[ind-1] + neededby[ind];
9907
cols[k] = i-1;
9908
neededby[ind] += 1;
9909
}
9910
}
9911
}
9912
9913
if( step == 1 ) {
9914
rows = Ivector( 0, noknots );
9915
rows[0] = 0;
9916
for(i=1;i<=noknots;i++)
9917
rows[i] = rows[i-1] + neededby[i];
9918
9919
cols = Ivector( 0, totcon-1 );
9920
for(i=0;i<totcon;i++)
9921
cols[i] = 0;
9922
9923
invtopo->cols = cols;
9924
invtopo->rows = rows;
9925
invtopo->colsize = totcon;
9926
invtopo->rowsize = noknots;
9927
invtopo->created = TRUE;
9928
}
9929
}
9930
9931
minneeded = maxneeded = neededby[1];
9932
for(i=1;i<=noknots;i++) {
9933
minneeded = MIN( minneeded, neededby[i]);
9934
maxneeded = MAX( maxneeded, neededby[i]);
9935
}
9936
9937
free_Ivector(neededby,1,noknots);
9938
9939
if(info) {
9940
printf("There are from %d to %d connections in the inverse topology.\n",minneeded,maxneeded);
9941
printf("Each node is in average in %.3f elements\n",1.0*totcon/noknots);
9942
}
9943
9944
return(0);
9945
}
9946
9947
9948
9949
int CreateDualGraph(struct FemType *data,int unconnected,int info)
9950
{
9951
int totcon,dcon,noelements,noknots,elemtype,nonodes,i,j,k,l,i2,m,ind,hit,ci,ci2;
9952
int dualmaxcon,invmaxcon,showgraph,freeelements,step,orphanelements,stat;
9953
int *elemconnect,*neededby;
9954
int *dualrow,*dualcol,dualsize,dualmaxelem,allocated;
9955
int *invrow,*invcol;
9956
struct CRSType *dualgraph;
9957
9958
if(info) printf("Creating a dual graph of the finite element mesh\n");
9959
9960
dualgraph = &data->dualgraph;
9961
if(dualgraph->created) {
9962
printf("The dual graph already exists!\n");
9963
return(1);
9964
}
9965
9966
CreateInverseTopology(data,info);
9967
9968
noelements = data->noelements;
9969
noknots = data->noknots;
9970
freeelements = noelements;
9971
orphanelements = 0;
9972
9973
/* If a dual graph only for the unconnected nodes is requested do that.
9974
Basically the connected nodes are omitted in the graph. */
9975
if( unconnected ) {
9976
if(info) printf("Removing connected nodes from the dual graph\n");
9977
if( data->nodeconnectexist ) {
9978
if(info) printf("Creating connected elements list from the connected nodes\n");
9979
SetConnectedElements(data,info);
9980
}
9981
if( data->elemconnectexist ) {
9982
elemconnect = data->elemconnect;
9983
freeelements -= data->elemconnectexist;
9984
}
9985
else {
9986
unconnected = FALSE;
9987
}
9988
if(info) printf("List of unconnected elements created\n");
9989
}
9990
9991
showgraph = FALSE;
9992
if(showgraph) printf("elemental graph ij pairs\n");
9993
9994
data->dualexists = TRUE;
9995
dualmaxcon = 0;
9996
dualmaxelem = 0;
9997
9998
invrow = data->invtopo.rows;
9999
invcol = data->invtopo.cols;
10000
10001
10002
/* This marker is used to identify the connections already accounted for */
10003
neededby = Ivector(1,freeelements);
10004
for(i=1;i<=freeelements;i++)
10005
neededby[i] = 0;
10006
10007
allocated = FALSE;
10008
omstart:
10009
10010
totcon = 0;
10011
10012
for(i=1;i<=noelements;i++) {
10013
if(showgraph) printf("%d :: ",i);
10014
10015
dcon = 0;
10016
elemtype = data->elementtypes[i];
10017
nonodes = data->elementtypes[i] % 100;
10018
10019
if( unconnected ) {
10020
ci = elemconnect[i];
10021
if( ci < 0 ) continue;
10022
}
10023
else {
10024
ci = i;
10025
}
10026
if(allocated) dualrow[ci-1] = totcon;
10027
10028
if(0) printf("i=%d %d\n",i,elemtype);
10029
10030
for(step=1;step<=2;step++) {
10031
for(j=0;j<nonodes;j++) {
10032
ind = data->topology[i][j];
10033
10034
if(0) printf("ind=%d\n",ind);
10035
10036
10037
for(k=invrow[ind-1];k<invrow[ind];k++) {
10038
i2 = invcol[k]+1;
10039
10040
if( i2 == i ) continue;
10041
10042
if( unconnected ) {
10043
ci2 = elemconnect[i2];
10044
if( ci2 < 0 ) continue;
10045
}
10046
else {
10047
ci2 = i2;
10048
}
10049
10050
/* In the first cycle mark the needed connections,
10051
and in the second cycle set the marker to zero for next round. */
10052
if( step == 1 ) {
10053
if( neededby[ci2] ) continue;
10054
neededby[ci2] = TRUE;
10055
10056
if(0) printf("ci ci2 = %d %d\n",ci,ci2);
10057
10058
/* If the dual graph has been allocated populate it */
10059
if(allocated) {
10060
dualcol[totcon] = ci2-1;
10061
}
10062
10063
dcon += 1;
10064
totcon += 1;
10065
if( dcon > dualmaxcon ) {
10066
dualmaxcon = dcon;
10067
dualmaxelem = i;
10068
}
10069
}
10070
else {
10071
neededby[ci2] = FALSE;
10072
}
10073
}
10074
}
10075
}
10076
if( dcon == 0 && allocated ) {
10077
orphanelements += 1;
10078
}
10079
}
10080
10081
if(allocated) {
10082
dualrow[dualsize] = totcon;
10083
}
10084
else {
10085
dualsize = freeelements;
10086
if(info) printf("Allocating for the dual graph for %d with %d connections\n",dualsize,totcon);
10087
dualrow = Ivector(0,dualsize);
10088
for(i=1;i<=dualsize;i++)
10089
dualrow[i] = 0;
10090
10091
dualcol = Ivector(0,totcon-1);
10092
for(i=0;i<totcon;i++)
10093
dualcol[i] = 0;
10094
10095
dualgraph->cols = dualcol;
10096
dualgraph->rows = dualrow;
10097
dualgraph->rowsize = dualsize;
10098
dualgraph->colsize = totcon;
10099
dualgraph->created = TRUE;
10100
10101
allocated = TRUE;
10102
10103
goto omstart;
10104
}
10105
10106
if( orphanelements && info ) {
10107
printf("There are %d elements in the dual mesh that are not connected!\n",orphanelements);
10108
if(unconnected) printf("The orphan elements are likely caused by the hybrid partitioning\n");
10109
}
10110
10111
10112
#if 0
10113
j = totcon; k = 0;
10114
for(i=1;i<=dualsize;i++){
10115
l = dualrow[i]-dualrow[i-1];
10116
if(l <= 0 ) printf("row(%d) = %d %d %d\n",i,l,dualrow[i],dualrow[i-1]);
10117
j = MIN(j,l);
10118
k = MAX(k,l);
10119
}
10120
printf("range dualrow: %d %d\n",j,k);
10121
10122
j = totcon; k = 0;
10123
for(i=0;i<totcon;i++) {
10124
j = MIN(j,dualcol[i]);
10125
k = MAX(k,dualcol[i]);
10126
}
10127
printf("range dualcol: %d %d\n",j,k);
10128
#endif
10129
10130
10131
if(info) {
10132
printf("There are at maximum %d connections in dual graph (in element %d).\n",dualmaxcon,dualmaxelem);
10133
printf("There are at all in all %d connections in dual graph.\n",totcon);
10134
printf("Average connection per active element in dual graph is %.3f\n",1.0*totcon/freeelements);
10135
}
10136
10137
free_Ivector( neededby,1,freeelements);
10138
10139
/* Inverse topology is created for partitioning only and then the direct
10140
topology is needed elsewhere as well. Do do not destroy it. */
10141
if(0) stat = DestroyInverseTopology(data,info);
10142
10143
return(0);
10144
}
10145
10146
10147
int DestroyCRSMatrix(struct CRSType *sp) {
10148
10149
if(sp->created) {
10150
if(0) printf("You tried to destroy a non-existing sparse matrix\n");
10151
return(1);
10152
}
10153
10154
free_Ivector( sp->rows, 0, sp->rowsize );
10155
free_Ivector( sp->cols, 0, sp->colsize-1);
10156
sp->rowsize = 0;
10157
sp->colsize = 0;
10158
sp->created = FALSE;
10159
10160
return(0);
10161
}
10162
10163
10164
int DestroyInverseTopology(struct FemType *data,int info)
10165
{
10166
int stat;
10167
stat = DestroyCRSMatrix( &data->invtopo );
10168
return(stat);
10169
}
10170
10171
int DestroyDualGraph(struct FemType *data,int info)
10172
{
10173
int stat;
10174
stat = DestroyCRSMatrix( &data->dualgraph );
10175
return(stat);
10176
}
10177
10178
10179
10180
10181
int MeshTypeStatistics(struct FemType *data,int info)
10182
{
10183
int i,elemtype,maxelemtype,minelemtype;
10184
int *elemtypes=NULL;
10185
10186
maxelemtype = minelemtype = data->elementtypes[1];
10187
10188
for(i=1;i<=data->noelements;i++) {
10189
elemtype = data->elementtypes[i];
10190
maxelemtype = MAX( maxelemtype, elemtype );
10191
minelemtype = MIN( minelemtype, elemtype );
10192
}
10193
10194
elemtypes = Ivector(minelemtype,maxelemtype);
10195
for(i=minelemtype;i<=maxelemtype;i++)
10196
elemtypes[i] = 0;
10197
10198
for(i=1;i<=data->noelements;i++) {
10199
elemtype = data->elementtypes[i];
10200
elemtypes[elemtype] += 1;
10201
}
10202
10203
if(info) {
10204
printf("Number of different elementtypes\n");
10205
for(i=minelemtype;i<=maxelemtype;i++)
10206
if(elemtypes[i]) printf("\t%d\t%d\n",i,elemtypes[i]);
10207
}
10208
10209
free_Ivector(elemtypes,minelemtype,maxelemtype);
10210
return(0);
10211
}
10212
10213
int BoundingBox(struct FemType *data,int nomesh,int nomeshes,int info)
10214
{
10215
int i;
10216
Real xmin, xmax, ymin, ymax, zmin, zmax, sidemax;
10217
10218
xmin = xmax = data->x[1];
10219
ymin = ymax = data->y[1];
10220
zmin = zmax = data->z[1];
10221
10222
for(i=1; i<=data->noknots; i++){
10223
xmax = MAX( xmax, data->x[i] );
10224
xmin = MIN( xmin, data->x[i] );
10225
ymax = MAX( ymax, data->y[i] );
10226
ymin = MIN( ymin, data->y[i] );
10227
zmax = MAX( zmax, data->z[i] );
10228
zmin = MIN( zmin, data->z[i] );
10229
}
10230
sidemax = MAX(xmax-xmin,ymax-ymin);
10231
sidemax = MAX(sidemax,zmax-zmin);
10232
10233
if(nomeshes > 1) {
10234
printf("Bounding box of all nodes in mesh[%d] of [%d] meshes:\n",nomesh,nomeshes);
10235
}
10236
else {
10237
printf("Bounding box of all nodes in mesh:\n");
10238
}
10239
10240
printf("X:[%lg,%lg] ",xmin,xmax);
10241
printf("Y:[%lg,%lg] ",ymin,ymax);
10242
printf("Z:[%lg,%lg]\n",zmin,zmax);
10243
10244
if(sidemax > 49.9) {
10245
printf("\nNotice: the longest bounding box side length of [%lg] is greater than 50.\n",sidemax);
10246
printf("ElmerGUI includes a library of material properties, defined in SI units. If using ElmerGUI, \n");
10247
printf("then the geometry is expected to have meters as length. Geometry that exceeds 50 meters \n");
10248
printf("in length or width or height may not be intended. Many Geometry generators assume \n");
10249
printf("millimeters as the basic unit of length. Scaling the geometry from millimeters to meters \n");
10250
printf("may be the desired action. For more help, search the Elmer users forum for posts \n");
10251
printf("about SI units, or for posts about Coordinate Scaling.\n");
10252
printf("Scaling can be accomplished in at least three ways, as follows:\n");
10253
printf(" 1. Define the original geometry in meters, not millimeters.\n");
10254
printf(" 2. Call ElmerGrid with -scale 0.001 0.001 0.001 as an option.\n");
10255
printf(" 3. Add Coordinate Scaling = 0.001 to the simulation section of the sif file.\n");
10256
printf("If using Elmer to analyze large geometry, such as a glacier, then ignore this notice.\n\n");
10257
}
10258
10259
return(0);
10260
}
10261
10262