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