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