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