1 /*************************************************************************
2  *                                                                       *
3  * Vega FEM Simulation Library Version 3.1                               *
4  *                                                                       *
5  * "volumetricMesh" library , Copyright (C) 2007 CMU, 2009 MIT, 2016 USC *
6  * All rights reserved.                                                  *
7  *                                                                       *
8  * Code authors: Jernej Barbic, Yijing Li                                *
9  * http://www.jernejbarbic.com/code                                      *
10  *                                                                       *
11  * Research: Jernej Barbic, Fun Shing Sin, Daniel Schroeder,             *
12  *           Doug L. James, Jovan Popovic                                *
13  *                                                                       *
14  * Funding: National Science Foundation, Link Foundation,                *
15  *          Singapore-MIT GAMBIT Game Lab,                               *
16  *          Zumberge Research and Innovation Fund at USC                 *
17  *                                                                       *
18  * This library is free software; you can redistribute it and/or         *
19  * modify it under the terms of the BSD-style license that is            *
20  * included with this library in the file LICENSE.txt                    *
21  *                                                                       *
22  * This library is distributed in the hope that it will be useful,       *
23  * but WITHOUT ANY WARRANTY; without even the implied warranty of        *
24  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the file     *
25  * LICENSE.TXT for more details.                                         *
26  *                                                                       *
27  *************************************************************************/
28 
29 #include <float.h>
30 #include <string.h>
31 #include <assert.h>
32 #include <iostream>
33 #include <map>
34 #include "volumetricMeshParser.h"
35 #include "volumetricMesh.h"
36 #include "volumetricMeshENuMaterial.h"
37 #include "volumetricMeshOrthotropicMaterial.h"
38 #include "volumetricMeshMooneyRivlinMaterial.h"
39 using namespace std;
40 
41 double VolumetricMesh::density_default = 1000;
42 double VolumetricMesh::E_default = 1E9;
43 double VolumetricMesh::nu_default = 0.45;
44 
45 // parses the mesh, and returns the string corresponding to the element type
VolumetricMesh(const char * filename,fileFormatType fileFormat,int numElementVertices_,elementType * elementType_,int verbose)46 VolumetricMesh::VolumetricMesh(const char * filename, fileFormatType fileFormat, int numElementVertices_, elementType * elementType_, int verbose): numElementVertices(numElementVertices_)
47 {
48   if (verbose)
49   {
50     printf("Opening file %s.\n", filename); fflush(NULL);
51   }
52 
53   switch (fileFormat)
54   {
55     case ASCII:
56       loadFromAscii(filename, elementType_);
57     break;
58 
59     case BINARY:
60       loadFromBinary(filename, elementType_);
61     break;
62 
63     default:
64       printf("Error in VolumetricMesh::VolumetricMesh: file format is unknown.\n");
65     break;
66   }
67 }
68 
69 // parses the mesh, and returns the string corresponding to the element type
VolumetricMesh(void * binaryInputStream,int numElementVertices_,elementType * elementType_,int memoryLoad)70 VolumetricMesh::VolumetricMesh(void * binaryInputStream, int numElementVertices_, elementType * elementType_, int memoryLoad): numElementVertices(numElementVertices_)
71 {
72   if (memoryLoad)
73     loadFromMemory((unsigned char *)binaryInputStream, elementType_);
74   else
75     loadFromBinary((FILE *)binaryInputStream, elementType_);
76 }
77 
~VolumetricMesh()78 VolumetricMesh::~VolumetricMesh()
79 {
80   delete [] vertices;
81 
82   for(int i=0; i<numElements; i++)
83     free(elements[i]);
84   free(elements);
85 
86   for(int i=0; i<numMaterials; i++)
87     delete(materials[i]);
88   free(materials);
89 
90   for(int i=0; i<numSets; i++)
91     delete(sets[i]);
92   free(sets);
93 
94   for(int i=0; i<numRegions; i++)
95     delete(regions[i]);
96   free(regions);
97 
98   free(elementMaterial);
99 }
100 
assignMaterialsToElements(int verbose)101 void VolumetricMesh::assignMaterialsToElements(int verbose)
102 {
103   elementMaterial = (int*) malloc (sizeof(int) * numElements);
104   for(int el=0; el<numElements; el++)
105     elementMaterial[el] = numMaterials;
106 
107   propagateRegionsToElements();
108 
109   // seek for unassigned elements
110   set<int> unassignedElements;
111   for(int el=0; el<numElements; el++)
112   {
113     if (elementMaterial[el] == numMaterials)
114       unassignedElements.insert(el);
115   }
116 
117   if (unassignedElements.size() > 0)
118   {
119     // assign set and region to the unassigned elements
120 
121     // create a material if none exists
122     if (numMaterials == 0)
123     {
124       numMaterials++;
125       materials = (Material**) realloc (materials, sizeof(Material*) * numMaterials);
126       materials[numMaterials - 1] = new ENuMaterial("defaultMaterial", density_default, E_default, nu_default);
127     }
128 
129     numSets++;
130     sets = (Set**) realloc (sets, sizeof(Set*) * numSets);
131     sets[numSets-1] = new Set("unassignedSet");
132     for(set<int>::iterator iter = unassignedElements.begin(); iter != unassignedElements.end(); iter++)
133       sets[numSets-1]->insert(*iter); // elements in sets are 0-indexed
134 
135     // create a new region for the unassigned elements
136     numRegions++;
137     regions = (Region**) realloc (regions, sizeof(Region*) * numRegions);
138     regions[numRegions - 1] = new Region(numMaterials - 1, numSets - 1);
139 
140     for(set<int>::iterator iter = unassignedElements.begin(); iter != unassignedElements.end(); iter++)
141       elementMaterial[*iter] = numMaterials - 1;
142 
143     if (verbose)
144       printf("Warning: %d elements were not found in any of the regions. Using default material parameters for these elements.\n", (int)unassignedElements.size());
145   }
146 }
147 
loadFromAscii(const char * filename,elementType * elementType_,int verbose)148 void VolumetricMesh::loadFromAscii(const char * filename, elementType * elementType_, int verbose)
149 {
150   // create buffer for element vertices
151   vector<int> elementVerticesBuffer(numElementVertices);
152   int * v = &elementVerticesBuffer[0];
153 
154 
155   // parse the .veg file
156   VolumetricMeshParser volumetricMeshParser;
157 
158   if (volumetricMeshParser.open(filename) != 0)
159   {
160     printf("Error: could not open file %s.\n",filename);
161     throw 1;
162   }
163 
164   // === First pass: parse vertices and elements, and count the number of materials, sets and regions  ===
165 
166   int countNumVertices = 0;
167   int countNumElements = 0;
168 
169   numElements = -1;
170   numMaterials = 0;
171   numSets = 1; // set 0 is "allElements"
172   numRegions = 0;
173   *elementType_ = INVALID;
174   int parseState = 0;
175   char lineBuffer[1024];
176 
177   int oneIndexedVertices = 1;
178   int oneIndexedElements = 1;
179   while (volumetricMeshParser.getNextLine(lineBuffer, 0, 0) != NULL)
180   {
181     //lineBuffer now contains the next line
182     //printf("%s\n", lineBuffer);
183 
184     // find *VERTICES
185     if ((parseState == 0) && (strncmp(lineBuffer, "*VERTICES", 9) == 0))
186     {
187       parseState = 1;
188 
189       if (volumetricMeshParser.getNextLine(lineBuffer, 0, 0) != NULL)
190       {
191         // format is numVertices, 3, 0, 0
192         sscanf(lineBuffer, "%d", &numVertices);  // ignore 3, 0, 0
193         vertices = new Vec3d [numVertices];
194       }
195       else
196       {
197         printf("Error: file %s is not in the .veg format. Offending line:\n%s\n", filename, lineBuffer);
198         throw 2;
199       }
200 
201       continue;
202     }
203 
204     // find *ELEMENTS
205     if ((parseState == 1) && (strncmp(lineBuffer, "*ELEMENTS", 9) == 0))
206     {
207       parseState = 2;
208 
209       // parse element type
210       if (volumetricMeshParser.getNextLine(lineBuffer) != NULL)
211       {
212         volumetricMeshParser.removeWhitespace(lineBuffer);
213 
214         if (strncmp(lineBuffer, "TET", 3) == 0)
215           *elementType_ = TET;
216         else if (strncmp(lineBuffer, "CUBIC", 5) == 0)
217           *elementType_ = CUBIC;
218         else
219         {
220           printf("Error: unknown mesh type %s in file %s\n", lineBuffer, filename);
221           throw 3;
222         }
223       }
224       else
225       {
226         printf("Error: file %s is not in the .veg format. Offending line:\n%s\n", filename, lineBuffer);
227         throw 4;
228       }
229 
230       // parse the number of elements
231       if (volumetricMeshParser.getNextLine(lineBuffer, 0, 0) != NULL)
232       {
233         // format is: numElements, numElementVertices, 0
234         sscanf(lineBuffer, "%d", &numElements);  // only use numElements; ignore numElementVertices, 0
235         elements = (int**) malloc (sizeof(int*) * numElements);
236       }
237       else
238       {
239         printf("Error: file %s is not in the .veg format. Offending line:\n%s\n", filename, lineBuffer);
240         throw 5;
241       }
242 
243       continue;
244     }
245 
246     if ((parseState == 2) && (lineBuffer[0] == '*'))
247     {
248       parseState = 3; // end of elements
249     }
250 
251     if (parseState == 1)
252     {
253       // read the vertex position
254       if (countNumVertices >= numVertices)
255       {
256         printf("Error: mismatch in the number of vertices in %s.\n", filename);
257         throw 6;
258       }
259 
260       // ignore space, comma or tab
261       char * ch = lineBuffer;
262       while((*ch == ' ') || (*ch == ',') || (*ch == '\t'))
263         ch++;
264 
265       int index;
266       sscanf(ch, "%d", &index);
267       // seek next separator
268       while((*ch != ' ') && (*ch != ',') && (*ch != '\t') && (*ch != 0))
269         ch++;
270 
271       if (index == 0)
272         oneIndexedVertices = 0; // input mesh has 0-indexed vertices
273 
274       double pos[3];
275       for(int i=0; i<3; i++)
276       {
277         // ignore space, comma or tab
278         while((*ch == ' ') || (*ch == ',') || (*ch == '\t'))
279           ch++;
280 
281         if (*ch == 0)
282         {
283           printf("Error parsing line %s in file %s.\n", lineBuffer, filename);
284           throw 7;
285         }
286 
287         sscanf(ch, "%lf", &pos[i]);
288 
289         // seek next separator
290         while((*ch != ' ') && (*ch != ',') && (*ch != '\t') && (*ch != 0))
291           ch++;
292       }
293 
294       vertices[countNumVertices] = Vec3d(pos);
295       countNumVertices++;
296     }
297 
298     if (parseState == 2)
299     {
300       // read the element vertices
301       if (countNumElements >= numElements)
302       {
303         printf("Error: mismatch in the number of elements in %s.\n", filename);
304         throw 8;
305       }
306 
307       // ignore space, comma or tab
308       char * ch = lineBuffer;
309       while((*ch == ' ') || (*ch == ',') || (*ch == '\t'))
310         ch++;
311 
312       int index;
313       sscanf(ch, "%d", &index);
314 
315       if (index == 0)
316         oneIndexedElements = 0; // input mesh has 0-indexed elements
317 
318       // seek next separator
319       while((*ch != ' ') && (*ch != ',') && (*ch != '\t') && (*ch != 0))
320         ch++;
321 
322       for(int i=0; i<numElementVertices; i++)
323       {
324         // ignore space, comma or tab
325         while((*ch == ' ') || (*ch == ',') || (*ch == '\t'))
326           ch++;
327 
328         if (*ch == 0)
329         {
330           printf("Error parsing line %s in file %s.\n", lineBuffer, filename);
331           throw 9;
332         }
333 
334         sscanf(ch, "%d", &v[i]);
335 
336         // seek next separator
337         while((*ch != ' ') && (*ch != ',') && (*ch != '\t') && (*ch != 0))
338           ch++;
339       }
340 
341       // if vertices were 1-numbered in the .veg file, convert to 0-numbered
342       for (int k=0; k<numElementVertices; k++)
343         v[k] -= oneIndexedVertices;
344 
345       elements[countNumElements] = (int*) malloc (sizeof(int) * numElementVertices);
346       for(int j=0; j<numElementVertices; j++)
347         elements[countNumElements][j] = v[j];
348 
349       countNumElements++;
350     }
351 
352     if (strncmp(lineBuffer, "*MATERIAL", 9) == 0)
353     {
354       numMaterials++;
355       continue;
356     }
357 
358     if (strncmp(lineBuffer, "*SET", 4) == 0)
359     {
360       numSets++;
361       continue;
362     }
363 
364     if (strncmp(lineBuffer, "*REGION", 7) == 0)
365     {
366       numRegions++;
367       continue;
368     }
369   }
370 
371   if (numElements < 0)
372   {
373     printf("Error: incorrect number of elements.  File %s may not be in the .veg format.\n", filename);
374     throw 10;
375   }
376 
377   // === Second pass: parse materials, sets and regions ===
378 
379   volumetricMeshParser.rewindToStart();
380 
381   if (verbose)
382   {
383     if (numMaterials == 0)
384       printf("Warning: no materials encountered in %s.\n", filename);
385 
386     if (numRegions == 0)
387       printf("Warning: no regions encountered in %s.\n", filename);
388   }
389 
390   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
391   sets = (Set**) malloc (sizeof(Set*) * numSets);
392   regions = (Region**) malloc (sizeof(Region*) * numRegions);
393 
394   // create the "allElements" set, containing all the elements
395   sets[0] = new Set("allElements");
396   for(int el=0; el<numElements; el++)
397     sets[0]->insert(el);
398 
399   int countNumMaterials = 0;
400   int countNumSets = 1; // set 0 is "allElements"
401   int countNumRegions = 0;
402 
403   map<string,int> materialMap; // establishes a relationship between material's string name and its index in the "materials" array
404   map<string,int> setMap; // establishes a relationship between set's string name and its index in the "sets" array
405   setMap.insert(pair<string,int>(string("allElements"), 0));
406 
407   parseState = 0;
408 
409   while (volumetricMeshParser.getNextLine(lineBuffer, 0, 0) != NULL)
410   {
411     //printf("%s\n", lineBuffer);
412 
413     // exit parsing of comma-separated set elements upon the new * command
414     if ((parseState == 11) && (lineBuffer[0] == '*'))
415       parseState = 0;
416 
417     // parse material
418 
419     if ((parseState == 0) && (strncmp(lineBuffer, "*MATERIAL", 9) == 0))
420     {
421       volumetricMeshParser.removeWhitespace(lineBuffer);
422 
423       // read material name
424       char materialNameC[4096];
425       strcpy(materialNameC, &lineBuffer[9]);
426 
427       // read the material type
428       char materialSpecification[4096];
429       if (volumetricMeshParser.getNextLine(lineBuffer) != NULL)
430       {
431         volumetricMeshParser.removeWhitespace(lineBuffer);
432         sscanf(lineBuffer, "%s", materialSpecification);
433       }
434       else
435       {
436         printf("Error: incorrect material in file %s. Offending line:\n%s\n", filename, lineBuffer);
437         throw 11;
438       }
439 
440       // seek for first comma in the material type specification
441       char * ch = materialSpecification;
442       while((*ch != ',') && (*ch != 0))
443         ch++;
444 
445       if (*ch == 0)
446       {
447         printf("Error parsing file %s. Offending line: %s.\n", filename, lineBuffer);
448         throw 12;
449       }
450 
451       // ch now points to the first comma
452       // set the materialType (the string up to the first comma)
453       char materialType[4096];
454       unsigned int materialTypeLength = ch - materialSpecification;
455       memcpy(materialType, materialSpecification, sizeof(unsigned char) * materialTypeLength);
456       *(materialType + materialTypeLength) = 0;
457       // materialType is now set
458 
459       ch++;
460       // now, ch points to the first character after the comma
461 
462       if (strcmp(materialType, "ENU") == 0)
463       {
464         // material specified by E, nu, density
465         double density, E, nu;
466         sscanf(ch, "%lf,%lf,%lf", &density, &E, &nu);
467 
468         if ((E > 0) && (nu > -1.0) && (nu < 0.5) && (density > 0))
469         {
470           // create new material
471           string name(materialNameC);
472           materials[countNumMaterials] = new ENuMaterial(name, density, E, nu);
473           materialMap.insert(pair<string,int>(name, countNumMaterials));
474         }
475         else
476         {
477           printf("Error: incorrect material specification in file %s. Offending line: %s\n", filename, lineBuffer);
478           throw 13;
479         }
480       }
481       else if (strncmp(materialType, "ORTHOTROPIC", 11) == 0)
482       {
483         // orthotropic material
484         double density = 0.0, E1 = 0.0, E2 = 0.0, E3 = 0.0, nu12 = 0.0, nu23 = 0.0, nu31 = 0.0, G12 = 0.0, G23 = 0.0, G31 = 0.0;
485         double nu = 0.0, G = 1.0;
486         bool useNuAndG = false;
487         double R[9]; // rotation matrix, stored in row-major format
488         memset(R, 0, sizeof(R));
489         R[0] = R[4] = R[8] = 1.0; // default to identity
490 
491         // find subtype
492         char * subType = materialType + 11;
493         bool enoughParameters = false;
494 
495         if ((sscanf(ch,"%lf,%lf,%lf,%lf", &density, &E1, &E2, &E3) == 4)
496             && ((E1 > 0) && (E2 > 0) && (E3 > 0) && (density > 0)))
497         {
498           // move ch to the next parameters (skip over the four ones that were just read)
499           for(int i = 0; i < 4; i++)
500           {
501             while ((*ch != ',') && (*ch != 0))
502               ch++;
503             if (*ch == 0)
504               break;
505             ch++;
506           }
507           // ch now points to the first character of the fifth parameter, or \0 if there is no fifth parameter
508           // subtype points to the fitst character of the subtype suffix, or \0 if there is no suffix
509 
510           if ((*subType == 0) || (strcmp(subType, "_N3G3R9") == 0))
511           {
512             // there is no suffix (*ORTHOTROPIC), or suffix is *ORTHOTROPIC_N3G3R9
513             // parse nu12,nu23,nu31,G12,G23,G31,R0,R1,R2,R3,R4,R5,R6,R7,R8
514             if (sscanf(ch, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
515                 &nu12, &nu23, &nu31, &G12, &G23, &G31,
516                 &R[0], &R[1], &R[2], &R[3], &R[4], &R[5], &R[6], &R[7], &R[8]) == 15)
517               enoughParameters = true;
518           }
519           else if (strcmp(subType,"_N3G3") == 0)
520           {
521             // *ORTHOTROPIC_N3G3
522             // parse nu12,nu23,nu31,G12,G23,G31
523             // R is default (identity)
524             if (sscanf(ch, "%lf,%lf,%lf,%lf,%lf,%lf", &nu12, &nu23, &nu31, &G12, &G23, &G31) == 6)
525               enoughParameters = true;
526           }
527           else if (strcmp(subType,"_N1G1R9") == 0)
528           {
529             // *ORTHOTROPIC_N1G1R9
530             // parse nu,G,R0,R1,R2,R3,R4,R5,R6,R7,R8
531             if (sscanf(ch, "%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
532               &nu, &G, &R[0], &R[1], &R[2], &R[3], &R[4], &R[5], &R[6], &R[7], &R[8]) == 11)
533             {
534               useNuAndG = true;
535               enoughParameters = true;
536             }
537           }
538           else if (strcmp(subType, "_N1G1") == 0)
539           {
540             // *ORTHOTROPIC_N1G1
541             // parse nu,G
542             // R is default (identity)
543             if (sscanf(ch, "%lf,%lf",&nu,&G) == 2)
544             {
545               useNuAndG = true;
546               enoughParameters = true;
547             }
548           }
549           else if (strcmp(subType,"_N1R9") == 0)
550           {
551             // *ORTHOTROPIC_N1R9
552             // parse nu,R0,R1,R2,R3,R4,R5,R6,R7,R8
553             // G is default (1.0)
554             if (sscanf(ch,"%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf,%lf",
555                 &nu, &R[0], &R[1], &R[2], &R[3], &R[4], &R[5], &R[6], &R[7], &R[8]) == 10)
556             {
557               useNuAndG = true;
558               enoughParameters = true;
559             }
560           }
561           else if (strcmp(subType,"_N1") == 0)
562           {
563             // *ORTHOTROPIC_N1
564             // parse nu
565             // G is default (1.0)
566             // R is default (identity)
567             if (sscanf(ch,"%lf", &nu) == 1)
568             {
569               useNuAndG = true;
570               enoughParameters = true;
571             }
572           }
573           else
574           {
575             printf("Error: incorrect orthortropic material type \"%s\" in file %s. Offending line: %s\n", subType, filename, lineBuffer);
576             throw 14;
577           }
578 
579           if (useNuAndG && (nu > -1.0) && (nu < 0.5)) // if nu is not in this range, then G_ij is still 0, finally produce an error
580           {
581             // formulas from:
582             // Yijing Li, Jernej Barbic: Stable Corotational Materials, Symposium on Computer Animation 2014
583             nu12 = nu * sqrt(E1 / E2);
584             nu23 = nu * sqrt(E2 / E3);
585             nu31 = nu * sqrt(E3 / E1);
586             G12 = G * sqrt(E1 * E2) / (2.0 * (1.0 + nu));
587             G23 = G * sqrt(E2 * E3) / (2.0 * (1.0 + nu));
588             G31 = G * sqrt(E3 * E1) / (2.0 * (1.0 + nu));
589           }
590         } //end if (sscanf(ch,"%lf,%lf,%lf,%lf", &density, &E1, &E2, &E3) == 4 && (E1 > 0 && E2 > 0 && E3 > 0) )
591         // if the if clause failed, enoughParameters is now false
592 
593         if (enoughParameters && (G12 > 0) && (G23 > 0) && (G31 > 0))
594         {
595           // create new material
596           string name(materialNameC);
597           materials[countNumMaterials] = new OrthotropicMaterial(string(materialNameC), density, E1, E2, E3, nu12, nu23, nu31, G12, G23, G31, R);
598           materialMap.insert(pair<string,int>(name,countNumMaterials));
599         }
600         else
601         {
602           printf("Error: incorrect material specification in file %s. Offending line: %s\n", filename, lineBuffer);
603           throw 14;
604         }
605       }
606       else if (strncmp(materialType, "MOONEYRIVLIN", 12) == 0)
607       {
608         // mu01, m10, v1, density
609         double density, mu01, mu10, v1;
610         sscanf(ch, "%lf,%lf,%lf,%lf", &density, &mu01, &mu10, &v1);
611 
612         if (density > 0)
613         {
614           // create new material
615           string name(materialNameC);
616           materials[countNumMaterials] = new MooneyRivlinMaterial(name, density, mu01, mu10, v1);
617           materialMap.insert(pair<string,int>(name, countNumMaterials));
618         }
619         else
620         {
621           printf("Error: incorrect material specification in file %s. Offending line:\n%s\n", filename, lineBuffer);
622           throw 15;
623         }
624       }
625       else
626       {
627         printf("Error: incorrect material specification in file %s. Offending line:\n%s\n", filename, lineBuffer);
628         throw 16;
629       }
630 
631       countNumMaterials++;
632     }
633 
634     // parse region
635     if ((parseState == 0) && (strncmp(lineBuffer, "*REGION,", 7) == 0))
636     {
637       volumetricMeshParser.removeWhitespace(lineBuffer);
638 
639       char setNameC[4096];
640       char materialNameC[4096];
641 
642       if (volumetricMeshParser.getNextLine(lineBuffer) != NULL)
643       {
644         volumetricMeshParser.removeWhitespace(lineBuffer);
645 
646         // format is set, material
647         // seek for first comma
648         char * ch = lineBuffer;
649         while((*ch != ',') && (*ch != 0))
650           ch++;
651 
652         if (*ch == 0)
653         {
654           printf("Error parsing file %s. Offending line: %s.\n", filename, lineBuffer);
655           throw 17;
656         }
657 
658         // now, ch points to the comma
659         *ch = 0;
660         strcpy(setNameC, lineBuffer);
661         *ch = ','; // restore the lineBuffer
662         ch++;
663         strcpy(materialNameC, ch);
664       }
665       else
666       {
667         printf("Error: file %s is not in the .veg format. Offending line:\n%s\n", filename, lineBuffer);
668         throw 18;
669       }
670 
671       // seek for setNameC
672       int setNum = -1;
673       map<string,int>::iterator it = setMap.find(string(setNameC));
674       if (it != setMap.end())
675       {
676       	setNum = it->second;
677       }
678       else
679       {
680         printf("Error: set %s not found among the sets.\n", setNameC);
681         throw 19;
682       }
683 
684       // seek for materialNameC
685       int materialNum = -1;
686       it = materialMap.find(string(materialNameC));
687       if (it != materialMap.end())
688       {
689       	materialNum = it->second;
690       }
691       else
692       {
693       	printf("Error: material %s not found among the materials.\n", materialNameC);
694       	throw 20;
695       }
696 
697       // create a new region
698       regions[countNumRegions] = new Region(materialNum, setNum);
699       countNumRegions++;
700     }
701 
702     // parse set elements
703     if (parseState == 11)
704     {
705       // parse the next line of the comma-separated elements in the set
706       // we know that lineBuffer[0] != '*' (i.e., not the end of the list), as that case was already previously handled
707 
708       volumetricMeshParser.removeWhitespace(lineBuffer);
709       //printf("%s\n", lineBuffer);
710 
711       // parse the comma-separated line
712       char * pch;
713       pch = strtok(lineBuffer, ",");
714       while ((pch != NULL) && (isdigit(*pch)))
715       {
716         int newElement = atoi(pch);
717         int ind = newElement-oneIndexedElements;
718         if (ind >= numElements || ind < 0)
719         {
720           printf("Error: set element index: %d out of bounds.\n", newElement);
721           throw 21;
722         }
723         sets[countNumSets-1]->insert(ind); // sets are 0-indexed, but .veg files may be 1-indexed (oneIndexedElements == 1)
724         pch = strtok(NULL, ",");
725       }
726     }
727 
728     // parse set
729     if ((parseState == 0) && (strncmp(lineBuffer, "*SET", 4) == 0))
730     {
731       volumetricMeshParser.removeWhitespace(lineBuffer);
732 
733       string name(&lineBuffer[4]);
734       sets[countNumSets] = new Set(name);
735       setMap.insert(pair<string,int>(name, countNumSets));
736       countNumSets++;
737       parseState = 11;
738     }
739   }
740 
741   // === assign materials to elements and seek for unassigned elements ===
742   assignMaterialsToElements(verbose);
743 
744   volumetricMeshParser.close();
745 }
746 
VolumetricMesh(int numVertices_,double * vertices_,int numElements_,int numElementVertices_,int * elements_,double E,double nu,double density)747 VolumetricMesh::VolumetricMesh(int numVertices_, double * vertices_,
748                int numElements_, int numElementVertices_, int * elements_,
749                double E, double nu, double density): numElementVertices(numElementVertices_)
750 {
751   numElements = numElements_;
752   numVertices = numVertices_;
753 
754   numMaterials = 1;
755   numSets = 1;
756   numRegions = 1;
757 
758   vertices = new Vec3d [numVertices];
759   elements = (int**) malloc (sizeof(int*) * numElements);
760   elementMaterial = (int*) malloc (sizeof(int) * numElements);
761   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
762   sets = (Set**) malloc (sizeof(Set*) * numSets);
763   regions = (Region**) malloc (sizeof(Region*) * numRegions);
764 
765   for(int i=0; i<numVertices; i++)
766     vertices[i] = Vec3d(vertices_[3*i+0], vertices_[3*i+1], vertices_[3*i+2]);
767 
768   Material * material = new ENuMaterial("defaultMaterial", density, E, nu);
769   materials[0] = material;
770 
771   Set * set = new Set("allElements");
772 
773   int * v = (int*) malloc (sizeof(int) * numElementVertices);
774   for(int i=0; i<numElements; i++)
775   {
776     set->insert(i);
777     elements[i] = (int*) malloc (sizeof(int) * numElementVertices);
778     elementMaterial[i] = 0;
779     for(int j=0; j<numElementVertices; j++)
780     {
781       v[j] = elements_[numElementVertices * i + j];
782       elements[i][j] = v[j];
783     }
784   }
785   free(v);
786 
787   sets[0] = set;
788   Region * region = new Region(0, 0);
789   regions[0] = region;
790 }
791 
VolumetricMesh(int numVertices_,double * vertices_,int numElements_,int numElementVertices_,int * elements_,int numMaterials_,Material ** materials_,int numSets_,Set ** sets_,int numRegions_,Region ** regions_)792 VolumetricMesh::VolumetricMesh(int numVertices_, double * vertices_,
793          int numElements_, int numElementVertices_, int * elements_,
794          int numMaterials_, Material ** materials_,
795          int numSets_, Set ** sets_,
796          int numRegions_, Region ** regions_): numElementVertices(numElementVertices_)
797 {
798   numElements = numElements_;
799   numVertices = numVertices_;
800 
801   numMaterials = numMaterials_;
802   numSets = numSets_;
803   numRegions = numRegions_;
804 
805   vertices = new Vec3d [numVertices];
806   elements = (int**) malloc (sizeof(int*) * numElements);
807   elementMaterial = (int*) malloc (sizeof(int) * numElements);
808   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
809   sets = (Set**) malloc (sizeof(Set*) * numSets);
810   regions = (Region**) malloc (sizeof(Region*) * numRegions);
811 
812   for(int i=0; i<numVertices; i++)
813     vertices[i] = Vec3d(vertices_[3*i+0], vertices_[3*i+1], vertices_[3*i+2]);
814 
815   int * v = (int*) malloc (sizeof(int) * numElementVertices);
816   for(int i=0; i<numElements; i++)
817   {
818     elements[i] = (int*) malloc (sizeof(int) * numElementVertices);
819     for(int j=0; j<numElementVertices; j++)
820     {
821       v[j] = elements_[numElementVertices * i + j];
822       elements[i][j] = v[j];
823     }
824   }
825   free(v);
826 
827   for(int i=0; i<numMaterials; i++)
828     materials[i] = materials_[i]->clone();
829 
830   for(int i=0; i<numSets; i++)
831     sets[i] = new Set(*(sets_[i]));
832 
833   for(int i=0; i<numRegions; i++)
834     regions[i] = new Region(*(regions_[i]));
835 
836   // set elementMaterial:
837   propagateRegionsToElements();
838 }
839 
loadFromMemory(unsigned char * binaryInputStream,elementType * elementType_)840 void VolumetricMesh::loadFromMemory(unsigned char * binaryInputStream, elementType * elementType_)
841 {
842   int memoryLoad = 1;
843   loadFromBinaryGeneric((void*)binaryInputStream, elementType_, memoryLoad);
844 }
845 
loadFromBinary(FILE * binaryInputStream,elementType * elementType_)846 void VolumetricMesh::loadFromBinary(FILE * binaryInputStream, elementType * elementType_)
847 {
848   int memoryLoad = 0;
849   loadFromBinaryGeneric((void*)binaryInputStream, elementType_, memoryLoad);
850 }
851 
loadFromBinaryGeneric(void * binaryInputStream_,elementType * elementType_,int memoryLoad)852 void VolumetricMesh::loadFromBinaryGeneric(void * binaryInputStream_, elementType * elementType_, int memoryLoad)
853 {
854   unsigned int (*genericRead)(void *, unsigned int, unsigned int, void *);
855 
856   void * binaryInputStream;
857   if (memoryLoad)
858   {
859     genericRead = &VolumetricMesh::readFromMemory;
860     binaryInputStream = &(binaryInputStream_);
861   }
862   else
863   {
864     genericRead = &VolumetricMesh::readFromFile;
865     binaryInputStream = binaryInputStream_;
866   }
867 
868   double version;
869   if ((int)genericRead(&version, sizeof(double), 1, binaryInputStream) != 1)
870   {
871     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read version.\n");
872     throw 0;
873   };
874 
875   int eleType;
876   if ((int)genericRead(&eleType, sizeof(int), 1, binaryInputStream) != 1)
877   {
878     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read element type.\n");
879     throw 0;
880   };
881 
882   switch (eleType)
883   {
884     case TET:
885       *elementType_ = TET;
886       break;
887     case CUBIC:
888       *elementType_ = CUBIC;
889       break;
890     default:
891       printf("Error in VolumetricMesh::loadFromBinaryGeneric: unknown mesh type %d in file stream\n", eleType);
892       throw 2;
893       break;
894   }
895 
896   // input the number of vertices
897   if ((int)genericRead(&numVertices, sizeof(int), 1, binaryInputStream) != 1)
898   {
899     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read numVertices.\n");
900     throw 0;
901   }
902 
903   if (numVertices < 0)
904   {
905     printf("Error in VolumetricMesh::loadFromBinaryGeneric: incorrect number of vertices.\n");
906     throw 3;
907   }
908 
909   vertices = new Vec3d [numVertices];
910 
911   // input all the vertices
912   double * doubleTempVec = (double *) malloc (sizeof(double) * 3 * numVertices);
913   if ((int)genericRead(doubleTempVec, sizeof(double), 3 * numVertices, binaryInputStream) != 3 * numVertices)
914   {
915     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read vertex coordinates.\n");
916     throw 0;
917   }
918 
919   for(int vertexIndex=0; vertexIndex<numVertices; vertexIndex++)
920   {
921     vertices[vertexIndex] = Vec3d(&doubleTempVec[vertexIndex*3]);
922   }
923   free(doubleTempVec);
924 
925   // input the number of elements
926   if ((int)genericRead(&numElements, sizeof(int), 1, binaryInputStream) != 1)
927   {
928     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read numElements.\n");
929     throw 0;
930   }
931 
932   if (numElements < 0)
933   {
934     printf("Error in VolumetricMesh::loadFromBinaryGeneric: incorrect number of elements.\n");
935     throw 4;
936   }
937   // input the number of vertices of every element
938   int numEleVer;
939   if ((int)genericRead(&numEleVer, sizeof(int), 1, binaryInputStream) != 1)
940   {
941     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read number of vertices in every element.\n");
942     throw 0;
943   }
944 
945   if (numElementVertices > 0 && numEleVer != numElementVertices)
946   {
947     printf("Error in VolumetricMesh::loadFromBinaryGeneric: mismatch in the number of vertices of every element from file stream.\n");
948     throw 5;
949   }
950 
951   // input all elements
952   elements = (int**) malloc (sizeof(int*) * numElements);
953   int * intTempVec = (int *) malloc (sizeof(int) * numElementVertices * numElements);
954   if ((int)genericRead(intTempVec, sizeof(int), numElementVertices * numElements, binaryInputStream) != numElementVertices * numElements)
955   {
956     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the elements.\n");
957     throw 0;
958   }
959 
960   for(int elementIndex=0; elementIndex<numElements; elementIndex++)
961   {
962     elements[elementIndex] = (int*) malloc (sizeof(int) * numElementVertices);
963     memcpy(elements[elementIndex], &intTempVec[elementIndex * numElementVertices], sizeof(int) * numElementVertices);
964   }
965   free(intTempVec);
966 
967   // input number of materials
968   if ((int)genericRead(&numMaterials, sizeof(int), 1, binaryInputStream) != 1)
969   {
970     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the numMaterials.\n");
971     throw 0;
972   }
973 
974   if (numMaterials < 0)
975   {
976     printf("Error in VolumetricMesh::loadFromBinaryGeneric: incorrect number of materials.\n");
977     throw 6;
978   }
979   // input all the materials
980   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
981   for(int materialIndex=0; materialIndex<numMaterials; materialIndex++)
982   {
983     // input material name
984     char materialName[4096];
985     int length;
986     if ((int)genericRead(&length, sizeof(int), 1, binaryInputStream) != 1)
987     {
988       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the length of material name.\n");
989       throw 0;
990     }
991     if ((int)genericRead(materialName, sizeof(char), length, binaryInputStream) != length)
992     {
993       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the material name.\n");
994       throw 0;
995     }
996     materialName[length] = '\0';
997 
998     // input material type
999     int matType;
1000     if ((int)genericRead(&matType, sizeof(int), 1, binaryInputStream) != 1)
1001     {
1002       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the length of material type.\n");
1003       throw 0;
1004     }
1005 
1006     switch (matType)
1007     {
1008       case Material::ENU:
1009       {
1010         double materialProperty[Material::ENU_NUM_PROPERTIES];
1011         if ((int)genericRead(materialProperty, sizeof(double), Material::ENU_NUM_PROPERTIES, binaryInputStream) != Material::ENU_NUM_PROPERTIES)
1012         {
1013           printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the material properties (ENU).\n");
1014           throw 0;
1015         }
1016 
1017         if ((materialProperty[Material::ENU_E] > 0) && (materialProperty[Material::ENU_NU] > -1.0) && (materialProperty[Material::ENU_NU] < 0.5) && (materialProperty[Material::ENU_DENSITY] > 0))
1018         {
1019           // create new material
1020           materials[materialIndex] = new ENuMaterial(materialName, materialProperty[Material::ENU_DENSITY], materialProperty[Material::ENU_E], materialProperty[Material::ENU_NU]);
1021         }
1022         else
1023         {
1024           printf("Error in VolumetricMesh::loadFromBinaryGeneric: incorrect material specification in file stream.\n");
1025           throw 7;
1026         }
1027       }
1028       break;
1029 
1030       case Material::ORTHOTROPIC:
1031       {
1032         double materialProperty[Material::ORTHOTROPIC_NUM_PROPERTIES];
1033         if ((int)genericRead(materialProperty, sizeof(double), Material::ORTHOTROPIC_NUM_PROPERTIES, binaryInputStream) != Material::ORTHOTROPIC_NUM_PROPERTIES)
1034         {
1035           printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the material properties (ORTHOTROPIC).\n");
1036           throw 0;
1037         }
1038         double R[9];
1039         if ((int)genericRead(R, sizeof(double), 9, binaryInputStream) != 9)
1040         {
1041           printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the material properties (ORTHOTROPIC).\n");
1042           throw 0;
1043         }
1044         if ((materialProperty[Material::ORTHOTROPIC_E1] > 0) && (materialProperty[Material::ORTHOTROPIC_E2] > 0) && (materialProperty[Material::ORTHOTROPIC_E3] > 0) && (materialProperty[Material::ORTHOTROPIC_G12] > 0) && (materialProperty[Material::ORTHOTROPIC_G23] > 0) && (materialProperty[Material::ORTHOTROPIC_G31] > 0) && (materialProperty[Material::ORTHOTROPIC_DENSITY] > 0))
1045         {
1046           // create new material
1047           materials[materialIndex] = new OrthotropicMaterial(materialName, materialProperty[Material::ORTHOTROPIC_DENSITY], materialProperty[Material::ORTHOTROPIC_E1], materialProperty[Material::ORTHOTROPIC_E2], materialProperty[Material::ORTHOTROPIC_E3], materialProperty[Material::ORTHOTROPIC_NU12], materialProperty[Material::ORTHOTROPIC_NU23], materialProperty[Material::ORTHOTROPIC_NU31], materialProperty[Material::ORTHOTROPIC_G12], materialProperty[Material::ORTHOTROPIC_G23], materialProperty[Material::ORTHOTROPIC_G31], R);
1048         }
1049         else
1050         {
1051           printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the material properties (ORTHOTROPIC).\n");
1052           throw 14;
1053         }
1054       }
1055       break;
1056 
1057       case Material::MOONEYRIVLIN:
1058       {
1059         double materialProperty[Material::MOONEYRIVLIN_NUM_PROPERTIES];
1060         if ((int)genericRead(materialProperty, sizeof(double), Material::MOONEYRIVLIN_NUM_PROPERTIES, binaryInputStream) != Material::MOONEYRIVLIN_NUM_PROPERTIES)
1061         {
1062           printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the material properties (MOONEYRIVLIN).\n");
1063           throw 0;
1064         }
1065         if (materialProperty[Material::MOONEYRIVLIN_DENSITY] > 0)
1066         {
1067           // create new material
1068           materials[materialIndex] = new MooneyRivlinMaterial(materialName, materialProperty[Material::MOONEYRIVLIN_DENSITY], materialProperty[Material::MOONEYRIVLIN_MU01], materialProperty[Material::MOONEYRIVLIN_MU10], materialProperty[Material::MOONEYRIVLIN_V1]);
1069         }
1070         else
1071         {
1072           printf("Error in VolumetricMesh::loadFromBinaryGeneric: incorrect material specification in file stream. \n");
1073           throw 8;
1074         }
1075       }
1076       break;
1077 
1078       default:
1079         printf("Error in VolumetricMesh::loadFromBinaryGeneric: material type %d is unknown.\n", matType);
1080         throw 9;
1081       break;
1082     }
1083   }  // for materialIndex
1084 
1085   // input the number of sets
1086   if ((int)genericRead(&numSets, sizeof(int), 1, binaryInputStream) != 1)
1087   {
1088     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the numSets.\n");
1089     throw 0;
1090   }
1091 
1092   sets = (Set**) malloc (sizeof(Set*) * numSets);
1093 
1094   // create the "allElements" set, containing all the elements
1095   sets[0] = new Set("allElements");
1096   for(int elementIndex=0; elementIndex<numElements; elementIndex++)
1097     sets[0]->insert(elementIndex);
1098 
1099   // input all the other sets (must start from set 1)
1100   for(int setIndex = 1; setIndex < numSets; setIndex++)
1101   {
1102     // input the name of the set
1103     char setName[4096];
1104     int length;
1105     if ((int)genericRead(&length, sizeof(int), 1, binaryInputStream) != 1)
1106     {
1107       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the length of the set name.\n");
1108       throw 0;
1109     }
1110 
1111     if ((int)genericRead(setName, sizeof(char), length, binaryInputStream) != length)
1112     {
1113       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the set name.\n");
1114       throw 0;
1115     }
1116     setName[length] = '\0';
1117     sets[setIndex] = new Set(setName);
1118 
1119     // input number of elements in the current set
1120     int cardinality;
1121     if ((int)genericRead(&cardinality, sizeof(int), 1, binaryInputStream) != 1)
1122     {
1123       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the number of elements in current set.\n");
1124       throw 0;
1125     }
1126     intTempVec = (int *) malloc (sizeof(int) * cardinality);
1127 
1128     // input all the elements in the current set
1129     if ((int)genericRead(intTempVec, sizeof(int), cardinality, binaryInputStream) != cardinality)
1130     {
1131       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the elements in current set.\n"); throw 0;
1132     }
1133 
1134     for(int setElementIndex=0; setElementIndex < cardinality; setElementIndex++)
1135       sets[setIndex]->insert(intTempVec[setElementIndex]);
1136     free(intTempVec);
1137   }
1138 
1139   // input the number of regions
1140   if ((int)genericRead(&numRegions, sizeof(int), 1, binaryInputStream) != 1)
1141   {
1142     printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the numRegions.\n");
1143     throw 0;
1144   }
1145 
1146   // input all the regions, for each region (material, set)
1147   regions = (Region**) malloc (sizeof(Region*) * numRegions);
1148   for(int regionIndex=0; regionIndex < numRegions; regionIndex++)
1149   {
1150     int materialIndex;
1151     if ((int)genericRead(&materialIndex, sizeof(int), 1, binaryInputStream) != 1)
1152     {
1153       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the materialIndex.\n");
1154       throw 0;
1155     }
1156     int setIndex;
1157     if ((int)genericRead(&setIndex, sizeof(int), 1, binaryInputStream) != 1)
1158     {
1159       printf("Error in VolumetricMesh::loadFromBinaryGeneric: cannot read the setIndex.\n");
1160       throw 0;
1161     }
1162     regions[regionIndex] = new Region(materialIndex, setIndex);
1163   } // for regionIndex
1164 
1165   // === assign materials to elements and handle the unassigned elements ===
1166   int verbose = 0;
1167   assignMaterialsToElements(verbose);
1168 }
1169 
VolumetricMesh(const VolumetricMesh & volumetricMesh)1170 VolumetricMesh::VolumetricMesh(const VolumetricMesh & volumetricMesh)
1171 {
1172   numVertices = volumetricMesh.numVertices;
1173   vertices = new Vec3d [numVertices];
1174   for(int i=0; i<numVertices; i++)
1175     vertices[i] = volumetricMesh.vertices[i];
1176 
1177   numElementVertices = volumetricMesh.numElementVertices;
1178   numElements = volumetricMesh.numElements;
1179   elements = (int**) malloc (sizeof(int*) * numElements);
1180   for(int i=0; i<numElements; i++)
1181   {
1182     elements[i] = (int*) malloc (sizeof(int) * numElementVertices);
1183     for(int j=0; j<numElementVertices; j++)
1184       elements[i][j] = (volumetricMesh.elements)[i][j];
1185   }
1186 
1187   numMaterials = volumetricMesh.numMaterials;
1188   numSets = volumetricMesh.numSets;
1189   numRegions = volumetricMesh.numRegions;
1190 
1191   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
1192   for(int i=0; i<numMaterials; i++)
1193     materials[i] = (volumetricMesh.materials)[i]->clone();
1194 
1195   sets = (Set**) malloc (sizeof(Set*) * numSets);
1196   for(int i=0; i<numSets; i++)
1197     sets[i] = new Set(*((volumetricMesh.sets)[i]));
1198 
1199   regions = (Region**) malloc (sizeof(Region*) * numRegions);
1200   for(int i=0; i<numRegions; i++)
1201     regions[i] = new Region((*(volumetricMesh.regions)[i]));
1202 
1203   elementMaterial = (int*) malloc (sizeof(int) * numElements);
1204   for(int i=0; i<numElements; i++)
1205     elementMaterial[i] = (volumetricMesh.elementMaterial)[i];
1206 }
1207 
loadFromBinary(const char * filename,elementType * elementType_)1208 void VolumetricMesh::loadFromBinary(const char * filename, elementType * elementType_)
1209 {
1210   FILE * fin = fopen(filename, "rb");
1211 
1212   if (fin == NULL)
1213   {
1214     printf("Error in VolumetricMesh::loadFromBinary: could not open file %s.\n",filename);
1215     throw 1;
1216   }
1217   loadFromBinary(fin, elementType_);
1218 
1219   fclose(fin);
1220 }
1221 
saveToAscii(const char * filename,elementType elementType_) const1222 int VolumetricMesh::saveToAscii(const char * filename, elementType elementType_) const // saves the mesh to a .veg file
1223 {
1224   FILE * fout = fopen(filename, "w");
1225   if (!fout)
1226   {
1227     printf("Error: could not write to %s.\n",filename);
1228     return 1;
1229   }
1230 
1231   fprintf(fout, "# Vega mesh file.\n");
1232   fprintf(fout, "# %d vertices, %d elements\n", numVertices, numElements);
1233   fprintf(fout, "\n");
1234 
1235   // write vertices
1236   fprintf(fout,"*VERTICES\n");
1237   fprintf(fout,"%d 3 0 0\n", numVertices);
1238 
1239   for(int i=0; i < numVertices; i++)
1240   {
1241     const Vec3d & v = getVertex(i);
1242     fprintf(fout,"%d %.15G %.15G %.15G\n", i+1, v[0], v[1], v[2]);
1243   }
1244   fprintf(fout, "\n");
1245 
1246   // write elements
1247   fprintf(fout,"*ELEMENTS\n");
1248 
1249   char elementName[4096] = "INVALID";
1250   if (elementType_ == TET)
1251     strcpy(elementName, "TET");
1252   if (elementType_ == CUBIC)
1253     strcpy(elementName, "CUBIC");
1254   fprintf(fout,"%s\n", elementName);
1255 
1256   fprintf(fout,"%d %d 0\n", numElements, numElementVertices);
1257 
1258   for(int el=0; el < numElements; el++)
1259   {
1260     fprintf(fout,"%d ", el+1);
1261     for(int j=0; j < numElementVertices; j++)
1262     {
1263       fprintf(fout, "%d", getVertexIndex(el, j) + 1);
1264       if (j != numElementVertices - 1)
1265         fprintf(fout," ");
1266     }
1267     fprintf(fout,"\n");
1268   }
1269   fprintf(fout, "\n");
1270 
1271   // write materials
1272   for(int materialIndex=0; materialIndex < numMaterials; materialIndex++)
1273   {
1274     string name = materials[materialIndex]->getName();
1275     fprintf(fout, "*MATERIAL %s\n", name.c_str());
1276 
1277     if (materials[materialIndex]->getType() == Material::ENU)
1278     {
1279       ENuMaterial * material = downcastENuMaterial(materials[materialIndex]);
1280       double density = material->getDensity();
1281       double E = material->getE();
1282       double nu = material->getNu();
1283       fprintf(fout, "ENU, %.15G, %.15G, %.15G\n", density, E, nu);
1284     }
1285 
1286     if (materials[materialIndex]->getType() == Material::ORTHOTROPIC)
1287     {
1288       OrthotropicMaterial * material = downcastOrthotropicMaterial(materials[materialIndex]);
1289       double density = material->getDensity();
1290 
1291       double E1 = material->getE1();
1292       double E2 = material->getE2();
1293       double E3 = material->getE3();
1294       double nu12 = material->getNu12();
1295       double nu23 = material->getNu23();
1296       double nu31 = material->getNu31();
1297       double G12 = material->getG12();
1298       double G23 = material->getG23();
1299       double G31 = material->getG31();
1300       double R[9];
1301       material->getR(R);
1302 
1303       fprintf(fout, "ORTHOTROPIC, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G, %.15G\n", density, E1, E2, E3, nu12, nu23, nu31, G12, G23, G31, R[0], R[1], R[2], R[3], R[4], R[5], R[6], R[7], R[8]);
1304     }
1305 
1306     if (materials[materialIndex]->getType() == Material::MOONEYRIVLIN)
1307     {
1308       MooneyRivlinMaterial * material = downcastMooneyRivlinMaterial(materials[materialIndex]);
1309       double density = material->getDensity();
1310       double mu01 = material->getmu01();
1311       double mu10 = material->getmu10();
1312       double v1 = material->getv1();
1313       fprintf(fout, "MOONEYRIVLIN, %.15G, %.15G, %.20G %.15G\n", density, mu01, mu10, v1);
1314     }
1315     fprintf(fout, "\n");
1316   }
1317 
1318   // write sets (skip the allElements set)
1319   for(int setIndex=1; setIndex < numSets; setIndex++)
1320   {
1321     string name = sets[setIndex]->getName();
1322     fprintf(fout, "*SET %s\n", name.c_str());
1323     set<int> setElements;
1324     sets[setIndex]->getElements(setElements);
1325     int count = 0;
1326     for(set<int>::iterator iter = setElements.begin(); iter != setElements.end(); iter++)
1327     {
1328       fprintf(fout, "%d, ", *iter + 1); // .veg files are 1-indexed
1329       count++;
1330       if (count == 8)
1331       {
1332         fprintf(fout, "\n");
1333         count = 0;
1334       }
1335     }
1336     if (count != 0)
1337       fprintf(fout, "\n");
1338     fprintf(fout, "\n");
1339   }
1340 
1341   // write regions
1342   for(int regionIndex=0; regionIndex < numRegions; regionIndex++)
1343   {
1344     int materialIndex = regions[regionIndex]->getMaterialIndex();
1345     int setIndex = regions[regionIndex]->getSetIndex();
1346 
1347     fprintf(fout, "*REGION\n");
1348     fprintf(fout, "%s, %s\n", sets[setIndex]->getName().c_str(), materials[materialIndex]->getName().c_str());
1349     fprintf(fout, "\n");
1350   }
1351 
1352   fclose(fout);
1353   return 0;
1354 }
1355 
save(const char * filename) const1356 int VolumetricMesh::save(const char * filename) const //  for backward compatibility
1357 {
1358   return saveToAscii(filename);
1359 }
1360 
saveToBinary(const char * filename,unsigned int * bytesWritten,elementType elementType_) const1361 int VolumetricMesh::saveToBinary(const char * filename, unsigned int * bytesWritten, elementType elementType_) const
1362 {
1363   FILE * fout = fopen(filename, "wb");
1364   if (!fout)
1365   {
1366     printf("Error: could not write to %s.\n", filename);
1367     return 1;
1368   }
1369   int code = saveToBinary(fout, bytesWritten, elementType_);
1370   fclose(fout);
1371   return code;
1372 }
1373 
readFromFile(void * buf,unsigned int elementSize,unsigned int numElements,void * fin)1374 unsigned int VolumetricMesh::readFromFile(void * buf, unsigned int elementSize, unsigned int numElements, void * fin)
1375 {
1376   return fread(buf, elementSize, numElements, (FILE*)fin);
1377 }
1378 
readFromMemory(void * buf,unsigned int elementSize,unsigned int numElements,void * memoryLocation_)1379 unsigned int VolumetricMesh::readFromMemory(void * buf, unsigned int elementSize, unsigned int numElements, void * memoryLocation_)
1380 {
1381   unsigned char * memoryLocation = (unsigned char *)(*(void **)(memoryLocation_));
1382   unsigned int numBytes = elementSize * numElements;
1383   memcpy(buf, memoryLocation, numBytes);
1384   (*(void **)(memoryLocation_)) = (void *)((unsigned char *)(*(void **)(memoryLocation_)) + numBytes);
1385   return numElements;
1386 }
1387 
saveToBinary(FILE * binaryOutputStream,unsigned int * bytesWritten,elementType elementType_,bool countBytesOnly) const1388 int VolumetricMesh::saveToBinary(FILE * binaryOutputStream, unsigned int * bytesWritten, elementType elementType_, bool countBytesOnly) const
1389 {
1390   unsigned int totalBytesWritten = 0;
1391   unsigned int itemsWritten;
1392 
1393   // output the binary file version (1x double)
1394   const double version = 1.0;
1395   itemsWritten = 1;
1396   if (!countBytesOnly)
1397     itemsWritten = fwrite(&version, sizeof(double), 1, binaryOutputStream);
1398   if (itemsWritten < 1)
1399     return 1;
1400   totalBytesWritten += itemsWritten * sizeof(double);
1401 
1402   // output the element type (1x int)
1403   int eleType = elementType_;
1404   itemsWritten = 1;
1405   if (!countBytesOnly)
1406     itemsWritten = fwrite(&eleType, sizeof(int), 1, binaryOutputStream);
1407   if (itemsWritten < 1)
1408     return 1;
1409   totalBytesWritten += itemsWritten * sizeof(int);
1410 
1411   // output the number of vertices (1x int)
1412   itemsWritten = 1;
1413   if (!countBytesOnly)
1414     itemsWritten = fwrite(&numVertices, sizeof(int), 1, binaryOutputStream);
1415   if (itemsWritten < 1)
1416     return 1;
1417   totalBytesWritten += itemsWritten * sizeof(int);
1418 
1419   // output the vertices (3 doubles x numVertices)
1420   for(int vertexIndex = 0; vertexIndex < numVertices; vertexIndex++)
1421   {
1422     const Vec3d & v = getVertex(vertexIndex);
1423     double v_array[3];
1424     v.convertToArray(v_array);
1425     itemsWritten = 3;
1426     if (!countBytesOnly)
1427       itemsWritten = fwrite(v_array, sizeof(double), 3, binaryOutputStream);
1428     if (itemsWritten < 3)
1429       return 1;
1430     totalBytesWritten += itemsWritten * sizeof(double);
1431   }
1432 
1433   // output the number of elements (1x int)
1434   itemsWritten = 1;
1435   if (!countBytesOnly)
1436     itemsWritten = fwrite(&numElements, sizeof(int), 1, binaryOutputStream);
1437   if (itemsWritten < 1)
1438     return 1;
1439   totalBytesWritten += itemsWritten * sizeof(int);
1440 
1441   // output the number of vertices of every element (1x int)
1442   itemsWritten = 1;
1443   if (!countBytesOnly)
1444     itemsWritten = fwrite(&numElementVertices, sizeof(int), 1, binaryOutputStream);
1445   if (itemsWritten < 1)
1446     return 1;
1447   totalBytesWritten += itemsWritten * sizeof(int);
1448 
1449   // output the vertex indices of every element
1450   for(int elementIndex = 0; elementIndex < numElements; elementIndex++)
1451   {
1452     for(int vertexIndex = 0; vertexIndex < numElementVertices; vertexIndex++)
1453     {
1454       int temp = getVertexIndex(elementIndex, vertexIndex);
1455       itemsWritten = 1;
1456       if (!countBytesOnly)
1457         itemsWritten = fwrite(&temp, sizeof(int), 1, binaryOutputStream);
1458       if (itemsWritten < 1)
1459         return 1;
1460       totalBytesWritten += itemsWritten * sizeof(int);
1461     }
1462   }
1463 
1464   // output the number of materials
1465   itemsWritten = 1;
1466   if (!countBytesOnly)
1467     itemsWritten = fwrite(&numMaterials, sizeof(int), 1, binaryOutputStream);
1468   if (itemsWritten < 1)
1469     return 1;
1470   totalBytesWritten += itemsWritten * sizeof(int);
1471 
1472   // output materials
1473   for(int materialIndex = 0; materialIndex < numMaterials; materialIndex++)
1474   {
1475     string name = materials[materialIndex]->getName();
1476     unsigned int length = name.size();
1477 
1478     // output material name
1479     itemsWritten = 1;
1480     if (!countBytesOnly)
1481       itemsWritten = fwrite(&length, sizeof(int), 1, binaryOutputStream); // write the length of the material name
1482     if (itemsWritten < 1)
1483       return 1;
1484     totalBytesWritten += itemsWritten * sizeof(int);
1485 
1486     itemsWritten = length;
1487     if (!countBytesOnly)
1488       itemsWritten = fwrite(name.c_str(), sizeof(char), length, binaryOutputStream);
1489     if (itemsWritten < length)
1490       return 1;
1491     totalBytesWritten += itemsWritten * sizeof(char);
1492 
1493     // output material type (1x int)
1494     int matType = materials[materialIndex]->getType();
1495 
1496     itemsWritten = 1;
1497     if (!countBytesOnly)
1498       itemsWritten = fwrite(&matType, sizeof(int), 1, binaryOutputStream);
1499     if (itemsWritten < 1)
1500       return 1;
1501     totalBytesWritten += itemsWritten * sizeof(int);
1502     switch (matType)
1503     {
1504       case Material::ENU:
1505       {
1506         ENuMaterial * material = downcastENuMaterial(materials[materialIndex]);
1507         double materialProperty[Material::ENU_NUM_PROPERTIES];
1508         materialProperty[Material::ENU_DENSITY] = material->getDensity();
1509         materialProperty[Material::ENU_E] = material->getE();
1510         materialProperty[Material::ENU_NU] = material->getNu();
1511 
1512         itemsWritten = Material::ENU_NUM_PROPERTIES;
1513         if (!countBytesOnly)
1514           itemsWritten = fwrite(materialProperty, sizeof(double), Material::ENU_NUM_PROPERTIES, binaryOutputStream);
1515         if (itemsWritten < Material::ENU_NUM_PROPERTIES)
1516           return 1;
1517         totalBytesWritten += itemsWritten * sizeof(double);
1518       }
1519       break;
1520 
1521       case Material::MOONEYRIVLIN:
1522       {
1523         MooneyRivlinMaterial * material = downcastMooneyRivlinMaterial(materials[materialIndex]);
1524         double materialProperty[Material::MOONEYRIVLIN_NUM_PROPERTIES];
1525         materialProperty[Material::MOONEYRIVLIN_DENSITY] = material->getDensity();
1526         materialProperty[Material::MOONEYRIVLIN_MU01] = material->getmu01();
1527         materialProperty[Material::MOONEYRIVLIN_MU10] = material->getmu10();
1528         materialProperty[Material::MOONEYRIVLIN_V1] = material->getv1();
1529 
1530         itemsWritten = Material::MOONEYRIVLIN_NUM_PROPERTIES;
1531         if (!countBytesOnly)
1532           itemsWritten = fwrite(materialProperty, sizeof(double), Material::MOONEYRIVLIN_NUM_PROPERTIES, binaryOutputStream);
1533         if (itemsWritten < Material::MOONEYRIVLIN_NUM_PROPERTIES)
1534           return 1;
1535         totalBytesWritten += itemsWritten * sizeof(double);
1536       }
1537       break;
1538 
1539       case Material::ORTHOTROPIC:
1540       {
1541         OrthotropicMaterial * material = downcastOrthotropicMaterial(materials[materialIndex]);
1542         double materialProperty[Material::ORTHOTROPIC_NUM_PROPERTIES];
1543         materialProperty[Material::ORTHOTROPIC_DENSITY] = material->getDensity();
1544         materialProperty[Material::ORTHOTROPIC_E1] = material->getE1();
1545         materialProperty[Material::ORTHOTROPIC_E2] = material->getE2();
1546         materialProperty[Material::ORTHOTROPIC_E3] = material->getE3();
1547         materialProperty[Material::ORTHOTROPIC_NU12] = material->getNu12();
1548         materialProperty[Material::ORTHOTROPIC_NU23] = material->getNu23();
1549         materialProperty[Material::ORTHOTROPIC_NU31] = material->getNu31();
1550         materialProperty[Material::ORTHOTROPIC_G12] = material->getG12();
1551         materialProperty[Material::ORTHOTROPIC_G23] = material->getG23();
1552         materialProperty[Material::ORTHOTROPIC_G31] = material->getG31();
1553 
1554         itemsWritten = Material::ORTHOTROPIC_NUM_PROPERTIES;
1555         if (!countBytesOnly)
1556           itemsWritten = fwrite(materialProperty, sizeof(double), Material::ORTHOTROPIC_NUM_PROPERTIES, binaryOutputStream);
1557         if (itemsWritten < Material::ORTHOTROPIC_NUM_PROPERTIES)
1558           return 1;
1559         totalBytesWritten += itemsWritten * sizeof(double);
1560 
1561         double R[9];
1562         material->getR(R);
1563 
1564         itemsWritten = 9;
1565         if (!countBytesOnly)
1566           itemsWritten = fwrite(R, sizeof(double), 9, binaryOutputStream);
1567         if (itemsWritten < 9)
1568           return 1;
1569         totalBytesWritten += itemsWritten * sizeof(double);
1570       }
1571       break;
1572 
1573       default:
1574       {
1575         printf("Error: material type %d is unknown.\n", matType);
1576           return 1;
1577       }
1578       break;
1579     }
1580 
1581   }  // for materialIndex
1582 
1583   // output the number of sets
1584   itemsWritten = 1;
1585   if (!countBytesOnly)
1586     itemsWritten = fwrite(&numSets, sizeof(int), 1, binaryOutputStream);
1587   if (itemsWritten < 1)
1588     return 1;
1589   totalBytesWritten += itemsWritten * sizeof(int);
1590 
1591   // output sets (skip the allElements set whose index is 0)
1592   for(int setIndex = 1; setIndex < numSets; setIndex++)
1593   {
1594     char * name = (char*) malloc (sizeof(char) * (sets[setIndex]->getName().length()+1));
1595     strcpy(name, sets[setIndex]->getName().c_str());
1596 
1597     // output the name of the set
1598     unsigned int length = strlen(name);
1599     itemsWritten = 1;
1600     if (!countBytesOnly)
1601       itemsWritten = fwrite(&length, sizeof(int), 1, binaryOutputStream);
1602     if (itemsWritten < 1)
1603       return 1;
1604     totalBytesWritten += itemsWritten * sizeof(int);
1605 
1606     itemsWritten = length;
1607     if (!countBytesOnly)
1608       itemsWritten = fwrite(name, sizeof(char), length, binaryOutputStream);
1609     if (itemsWritten < length)
1610       return 1;
1611     totalBytesWritten += itemsWritten * sizeof(char);
1612 
1613     std::set<int> setElements;
1614     sets[setIndex]->getElements(setElements);
1615 
1616     // output the number of elements in the current set
1617     unsigned int cardinality = setElements.size();
1618     itemsWritten = 1;
1619     if (!countBytesOnly)
1620       itemsWritten = fwrite(&cardinality, sizeof(int), 1, binaryOutputStream);
1621     if (itemsWritten < 1)
1622       return 1;
1623     totalBytesWritten += itemsWritten * sizeof(int);
1624 
1625     int * elementGroup = (int *) malloc (sizeof(int) * cardinality);
1626     int count = 0;
1627     for(std::set<int>::iterator iter = setElements.begin(); iter != setElements.end(); iter++)
1628     {
1629       elementGroup[count] = *iter;
1630       count++;
1631     }
1632     // output the current set
1633     itemsWritten = cardinality;
1634     if (!countBytesOnly)
1635       itemsWritten = fwrite(elementGroup, sizeof(int), cardinality, binaryOutputStream);
1636     if (itemsWritten < cardinality)
1637       return 1;
1638     totalBytesWritten += itemsWritten * sizeof(int);
1639     free(elementGroup);
1640 
1641     free(name);
1642   }  // for setIndex
1643 
1644   // output the number of regions
1645   itemsWritten = 1;
1646   if (!countBytesOnly)
1647     itemsWritten = fwrite(&numRegions, sizeof(int), 1, binaryOutputStream);
1648   if (itemsWritten < 1)
1649     return 1;
1650   totalBytesWritten += itemsWritten * sizeof(int);
1651 
1652   // output regions (for each region, output material and set)
1653   for(int regionIndex=0; regionIndex < numRegions; regionIndex++)
1654   {
1655     int materialIndex = regions[regionIndex]->getMaterialIndex();
1656     itemsWritten = 1;
1657     if (!countBytesOnly)
1658       itemsWritten = fwrite(&materialIndex, sizeof(int), 1, binaryOutputStream);
1659     if (itemsWritten < 1)
1660       return 1;
1661     totalBytesWritten += itemsWritten * sizeof(int);
1662 
1663     int setIndex = regions[regionIndex]->getSetIndex();
1664     itemsWritten = 1;
1665     if (!countBytesOnly)
1666       itemsWritten = fwrite(&setIndex, sizeof(int), 1, binaryOutputStream);
1667     if (itemsWritten < 1)
1668       return 1;
1669     totalBytesWritten += itemsWritten * sizeof(int);
1670   }
1671 
1672   if (bytesWritten != NULL)
1673     *bytesWritten = totalBytesWritten;
1674 
1675   return 0;
1676 }
1677 
getElementTypeASCII(const char * filename)1678 VolumetricMesh::elementType VolumetricMesh::getElementTypeASCII(const char * filename)
1679 {
1680   //printf("Parsing %s... (for element type determination)\n",filename);fflush(NULL);
1681   elementType elementType_;
1682 
1683   // parse the .veg file
1684   VolumetricMeshParser volumetricMeshParser;
1685   elementType_ = INVALID;
1686 
1687   if (volumetricMeshParser.open(filename) != 0)
1688   {
1689     printf("Error: could not open file %s.\n",filename);
1690     return elementType_;
1691   }
1692 
1693   char lineBuffer[1024];
1694   while (volumetricMeshParser.getNextLine(lineBuffer, 0, 0) != NULL)
1695   {
1696     //printf("%s\n", lineBuffer);
1697 
1698     // seek for *ELEMENTS
1699     if (strncmp(lineBuffer, "*ELEMENTS", 9) == 0)
1700     {
1701       // parse element type
1702       if (volumetricMeshParser.getNextLine(lineBuffer) != NULL)
1703       {
1704         volumetricMeshParser.removeWhitespace(lineBuffer);
1705 
1706         if (strncmp(lineBuffer, "TET", 3) == 0)
1707           elementType_ = TET;
1708         else if (strncmp(lineBuffer, "CUBIC", 5) == 0)
1709           elementType_ = CUBIC;
1710         else
1711         {
1712           printf("Error: unknown mesh type %s in file %s\n", lineBuffer, filename);
1713           return elementType_;
1714         }
1715       }
1716       else
1717       {
1718         printf("Error (getElementType): file %s is not in the .veg format. Offending line:\n%s\n", filename, lineBuffer);
1719         return elementType_;
1720       }
1721     }
1722   }
1723 
1724   volumetricMeshParser.close();
1725 
1726   if (elementType_ == INVALID)
1727     printf("Error: could not determine the mesh type in file %s. File may not be in .veg format.\n", filename);
1728 
1729   return elementType_;
1730 }
1731 
getElementTypeBinary(const char * filename)1732 VolumetricMesh::elementType VolumetricMesh::getElementTypeBinary(const char * filename)
1733 {
1734   FILE * fin = fopen(filename, "rb");
1735   if (fin == NULL)
1736   {
1737     printf("Error in VolumetricMesh::getElementTypeBinary: could not open file %s.\n",filename);
1738     exit(0);
1739   }
1740 
1741   elementType elementType_ = getElementType(fin);
1742   fclose(fin);
1743 
1744   return (elementType_);
1745 }
1746 
getElementType(const char * filename,fileFormatType fileFormat)1747 VolumetricMesh::elementType VolumetricMesh::getElementType(const char * filename, fileFormatType fileFormat)
1748 {
1749   switch (fileFormat)
1750   {
1751   case ASCII:
1752     return VolumetricMesh::getElementTypeASCII(filename);
1753   	break;
1754 
1755   case BINARY:
1756     return VolumetricMesh::getElementTypeBinary(filename);
1757     break;
1758 
1759   default:
1760     printf("Error: the file format %d is unknown. \n", fileFormat);
1761     exit(0);
1762     break;
1763   }
1764 }
1765 
getElementType(void * fin_,int memoryLoad)1766 VolumetricMesh::elementType VolumetricMesh::getElementType(void * fin_, int memoryLoad)
1767 {
1768   unsigned int (*genericRead)(void *, unsigned int, unsigned int, void *);
1769 
1770   void * fin;
1771   if (memoryLoad)
1772   {
1773     genericRead = &VolumetricMesh::readFromMemory;
1774     fin = &(fin_);
1775   }
1776   else
1777   {
1778     genericRead = &VolumetricMesh::readFromFile;
1779     fin = fin_;
1780   }
1781 
1782   double version;
1783   if ((int)genericRead(&version, sizeof(double), 1, fin) != 1)
1784   {
1785     printf("Error in VolumetricMesh::getElementType: cannot read version.\n");
1786     throw 0;
1787   };
1788 
1789   int eleType;
1790   if ((int)genericRead(&eleType, sizeof(int), 1, fin) != 1)
1791   {
1792     printf("Error in VolumetricMesh::getElementType: cannot read the element type from the stream\n");
1793     throw 1;
1794   }
1795 
1796   // rewind the size of an integer and a double
1797   if (memoryLoad)
1798   {
1799     fin = (void *)((unsigned char *)fin - ((int)sizeof(int)) - ((int)sizeof(double)));
1800   }
1801   else
1802   {
1803     int offset = -((int)sizeof(int)) - ((int)sizeof(double));
1804     fseek((FILE *)fin, offset, SEEK_CUR);
1805   }
1806 
1807   switch (eleType)
1808   {
1809     case TET:
1810       return TET;
1811     break;
1812 
1813     case CUBIC:
1814       return CUBIC;
1815     break;
1816 
1817     default:
1818       printf("Error: could not determine the mesh type from the stream.\n");
1819     break;
1820   }
1821 
1822   return INVALID;
1823 }
1824 
getVolume() const1825 double VolumetricMesh::getVolume() const
1826 {
1827   double vol = 0.0;
1828   for(int el=0; el<numElements; el++)
1829     vol += getElementVolume(el);
1830   return vol;
1831 }
1832 
getVertexVolumes(double * vertexVolumes) const1833 void VolumetricMesh::getVertexVolumes(double * vertexVolumes) const
1834 {
1835   memset(vertexVolumes, 0, sizeof(double) * numVertices);
1836   double factor = 1.0 / numElementVertices;
1837   for(int el=0; el<numElements; el++)
1838   {
1839     double volume = getElementVolume(el);
1840     for(int j=0; j<numElementVertices; j++)
1841       vertexVolumes[getVertexIndex(el, j)] += factor * volume;
1842   }
1843 }
1844 
getElementCenter(int el) const1845 Vec3d VolumetricMesh::getElementCenter(int el) const
1846 {
1847   Vec3d pos(0,0,0);
1848   for(int i=0; i<numElementVertices; i++)
1849     pos += getVertex(el,i);
1850 
1851   pos *= 1.0 / numElementVertices;
1852 
1853   return pos;
1854 }
1855 
getVerticesInElements(vector<int> & elements_,vector<int> & vertices_) const1856 void VolumetricMesh::getVerticesInElements(vector<int> & elements_, vector<int> & vertices_) const
1857 {
1858   set<int> ver;
1859   for(unsigned int i=0; i< elements_.size(); i++)
1860     for(int j=0; j< numElementVertices; j++)
1861       ver.insert(getVertexIndex(elements_[i],j));
1862 
1863   vertices_.clear();
1864   set<int>::iterator iter;
1865   for(iter = ver.begin(); iter != ver.end(); iter++)
1866     vertices_.push_back(*iter);
1867 }
1868 
getElementsTouchingVertices(vector<int> & vertices_,vector<int> & elements_) const1869 void VolumetricMesh::getElementsTouchingVertices(vector<int> & vertices_, vector<int> & elements_) const
1870 {
1871   set<int> ver;
1872   for(unsigned int i=0; i<vertices_.size(); i++)
1873     ver.insert(vertices_[i]);
1874 
1875   elements_.clear();
1876   for(int i=0; i< numElements; i++)
1877   {
1878     set<int> :: iterator iter;
1879     for(int j=0; j<numElementVertices; j++)
1880     {
1881       iter = ver.find(getVertexIndex(i,j));
1882       if (iter != ver.end())
1883       {
1884         elements_.push_back(i);
1885         break;
1886       }
1887     }
1888   }
1889 }
1890 
getVertexNeighborhood(vector<int> & vertices_,vector<int> & neighborhood) const1891 void VolumetricMesh::getVertexNeighborhood(vector<int> & vertices_, vector<int> & neighborhood) const
1892 {
1893   vector<int> elements_;
1894   getElementsTouchingVertices(vertices_, elements_);
1895   getVerticesInElements(elements_, neighborhood);
1896 }
1897 
getMass() const1898 double VolumetricMesh::getMass() const
1899 {
1900   double mass = 0.0;
1901   for(int i=0; i< getNumRegions(); i++)
1902   {
1903     const Region * region = getRegion(i);
1904     double density = getMaterial(region->getMaterialIndex())->getDensity();
1905     set<int> setElements; // elements in the region
1906     getSet(region->getSetIndex())->getElements(setElements);
1907 
1908     // over all elements in the region
1909     for(set<int> :: iterator iter = setElements.begin(); iter != setElements.end(); iter++)
1910     {
1911       int element = *iter;
1912       double elementVolume = getElementVolume(element);
1913       double elementMass = elementVolume * density;
1914       mass += elementMass;
1915     }
1916   }
1917 
1918   return mass;
1919 }
1920 
getInertiaParameters(double & mass,Vec3d & centerOfMass,Mat3d & inertiaTensor) const1921 void VolumetricMesh::getInertiaParameters(double & mass, Vec3d & centerOfMass, Mat3d & inertiaTensor) const
1922 {
1923   mass = 0.0;
1924   centerOfMass[0] = centerOfMass[1] = centerOfMass[2] = 0;
1925   inertiaTensor[0][0] = inertiaTensor[0][1] = inertiaTensor[0][2] = 0;
1926   inertiaTensor[1][0] = inertiaTensor[1][1] = inertiaTensor[1][2] = 0;
1927   inertiaTensor[2][0] = inertiaTensor[2][1] = inertiaTensor[2][2] = 0;
1928 
1929   // compute mass, center of mass, inertia tensor
1930   for(int i=0; i< getNumRegions(); i++)
1931   {
1932     const Region * region = getRegion(i);
1933     double density = getMaterial(region->getMaterialIndex())->getDensity();
1934     set<int> setElements; // elements in the region
1935     getSet(region->getSetIndex())->getElements(setElements);
1936 
1937     // over all elements in the region
1938     for(set<int> :: iterator iter = setElements.begin(); iter != setElements.end(); iter++)
1939     {
1940       int element = *iter;
1941       double elementVolume = getElementVolume(element);
1942       double elementMass = elementVolume * density;
1943 
1944       mass += elementMass;
1945       Vec3d elementCenter = getElementCenter(element);
1946       centerOfMass += elementMass * elementCenter;
1947 
1948       Mat3d elementITUnitDensity;
1949       getElementInertiaTensor(element, elementITUnitDensity);
1950 
1951       double a = elementCenter[0];
1952       double b = elementCenter[1];
1953       double c = elementCenter[2];
1954 
1955       Mat3d elementITCorrection
1956        (  b*b + c*c, -a*b, -a*c,
1957          -a*b, a*a + c*c, -b*c,
1958          -a*c, -b*c, a*a + b*b );
1959 
1960       Mat3d elementIT = density * elementITUnitDensity + elementMass * elementITCorrection;
1961 
1962       inertiaTensor += elementIT;
1963     }
1964   }
1965 
1966   //printf("final mass: %G\n",mass);
1967   centerOfMass /= mass;
1968 
1969   // correct inertia tensor so it's around the center of mass
1970   double a = centerOfMass[0];
1971   double b = centerOfMass[1];
1972   double c = centerOfMass[2];
1973 
1974   Mat3d correction
1975        ( b*b + c*c, -a*b, -a*c,
1976          -a*b, a*a + c*c, -b*c,
1977          -a*c, -b*c, a*a + b*b );
1978 
1979   inertiaTensor -= mass * correction;
1980 }
1981 
getMeshGeometricParameters(Vec3d & centroid,double * radius) const1982 void VolumetricMesh::getMeshGeometricParameters(Vec3d & centroid, double * radius) const
1983 {
1984   // compute centroid
1985   centroid = Vec3d(0, 0, 0);
1986   for(int i=0; i < numVertices ; i++)
1987     centroid += getVertex(i);
1988 
1989   centroid /= numVertices;
1990 
1991   // compute radius
1992   *radius = 0;
1993   for(int i=0; i < numVertices; i++)
1994   {
1995     Vec3d vertex = getVertex(i);
1996     double dist = len(vertex - centroid);
1997     if (dist > *radius)
1998       *radius = dist;
1999   }
2000 }
2001 
getClosestVertex(Vec3d pos) const2002 int VolumetricMesh::getClosestVertex(Vec3d pos) const
2003 {
2004   // linear scan
2005   double closestDist = DBL_MAX;
2006   int closestVertex = -1;
2007 
2008   for(int i=0; i<numVertices; i++)
2009   {
2010     const Vec3d & vertexPosition = vertices[i];
2011     double dist = len(pos - vertexPosition);
2012     if (dist < closestDist)
2013     {
2014       closestDist = dist;
2015       closestVertex = i;
2016     }
2017   }
2018 
2019   return closestVertex;
2020 }
2021 
getClosestElement(Vec3d pos) const2022 int VolumetricMesh::getClosestElement(Vec3d pos) const
2023 {
2024   // linear scan
2025   double closestDist = DBL_MAX;
2026   int closestElement = 0;
2027   for(int element=0; element < numElements; element++)
2028   {
2029     Vec3d center = getElementCenter(element);
2030     double dist = len(pos - center);
2031     if (dist < closestDist)
2032     {
2033       closestDist = dist;
2034       closestElement = element;
2035     }
2036   }
2037 
2038   return closestElement;
2039 }
2040 
getContainingElement(Vec3d pos) const2041 int VolumetricMesh::getContainingElement(Vec3d pos) const
2042 {
2043   // linear scan
2044   for(int element=0; element < numElements; element++)
2045   {
2046     if (containsVertex(element, pos))
2047       return element;
2048   }
2049 
2050   return -1;
2051 }
2052 
setSingleMaterial(double E,double nu,double density)2053 void VolumetricMesh::setSingleMaterial(double E, double nu, double density)
2054 {
2055   // erase previous materials
2056   for(int i=0; i<numMaterials; i++)
2057     delete(materials[i]);
2058   free(materials);
2059 
2060   for(int i=0; i<numSets; i++)
2061     delete(sets[i]);
2062   free(sets);
2063 
2064   for(int i=0; i<numRegions; i++)
2065     delete(regions[i]);
2066   free(regions);
2067 
2068   // add a single material
2069   numMaterials = 1;
2070   numSets = 1;
2071   numRegions = 1;
2072 
2073   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
2074   sets = (Set**) malloc (sizeof(Set*) * numSets);
2075   regions = (Region**) malloc (sizeof(Region*) * numRegions);
2076 
2077   Material * material = new ENuMaterial("defaultMaterial", density, E, nu);
2078   materials[0] = material;
2079 
2080   Set * set = new Set("allElements");
2081   for(int i=0; i<numElements; i++)
2082   {
2083     set->insert(i);
2084     elementMaterial[i] = 0;
2085   }
2086   sets[0] = set;
2087 
2088   Region * region = new Region(0, 0);
2089   regions[0] = region;
2090 }
2091 
getDefaultMaterial(double * E,double * nu,double * density)2092 void VolumetricMesh::getDefaultMaterial(double * E, double * nu, double * density)
2093 {
2094   *E = E_default;
2095   *nu = nu_default;
2096   *density = density_default;
2097 }
2098 
propagateRegionsToElements()2099 void VolumetricMesh::propagateRegionsToElements()
2100 {
2101   for(int regionIndex=0; regionIndex < numRegions; regionIndex++)
2102   {
2103     Region * region = regions[regionIndex];
2104     int materialIndex = region->getMaterialIndex();
2105 
2106     set<int> & setElements = sets[region->getSetIndex()]->getElements();
2107 
2108     for(set<int> :: iterator iter = setElements.begin(); iter != setElements.end(); iter++)
2109     {
2110       int elt = *iter;
2111       elementMaterial[elt] = materialIndex;
2112     }
2113   }
2114 }
2115 
generateInterpolationWeights(int numTargetLocations,const double * targetLocations,int * elements,int ** vertices_,double ** weights,double zeroThreshold,int verbose) const2116 int VolumetricMesh::generateInterpolationWeights(int numTargetLocations,
2117         const double * targetLocations, int * elements, int ** vertices_, double ** weights,
2118         double zeroThreshold, int verbose) const
2119 {
2120   // allocate interpolation arrays
2121   *vertices_ = (int*) malloc (sizeof(int) * numElementVertices * numTargetLocations);
2122   *weights = (double*) malloc (sizeof(double) * numElementVertices * numTargetLocations);
2123 
2124   double * barycentricWeights = (double*) malloc (sizeof(double) * numElementVertices);
2125 
2126   for (int i=0; i < numTargetLocations; i++) // over all interpolation locations
2127   {
2128     if ((verbose) && (i % 100 == 0))
2129     {
2130       printf("%d ", i); fflush(NULL);
2131     }
2132 
2133     Vec3d pos = Vec3d(targetLocations[3*i+0],
2134                       targetLocations[3*i+1],
2135                       targetLocations[3*i+2]);
2136 
2137     int element = elements[i];
2138     if (element < 0)
2139     {
2140       printf("Error: invalid element index %d.\n", element);
2141       return 1;
2142     }
2143 
2144     computeBarycentricWeights(element, pos, barycentricWeights);
2145 
2146     if (zeroThreshold > 0)
2147     {
2148       // check whether vertex is close enough to the mesh
2149       double minDistance = DBL_MAX;
2150       int numElementVertices = getNumElementVertices();
2151       int assignedZero = 0;
2152       for(int ii=0; ii< numElementVertices; ii++)
2153       {
2154         const Vec3d & vpos = getVertex(element, ii);
2155         if (len(vpos-pos) < minDistance)
2156         {
2157           minDistance = len(vpos-pos);
2158         }
2159       }
2160 
2161       if (minDistance > zeroThreshold)
2162       {
2163         // assign zero weights
2164         for(int ii=0; ii < numElementVertices; ii++)
2165           barycentricWeights[ii] = 0.0;
2166         assignedZero++;
2167         continue;
2168       }
2169     }
2170 
2171     for(int ii=0; ii<numElementVertices; ii++)
2172     {
2173       (*vertices_)[numElementVertices * i + ii] = getVertexIndex(element, ii);
2174       (*weights)[numElementVertices * i + ii] = barycentricWeights[ii];
2175     }
2176   }
2177 
2178   free(barycentricWeights);
2179 
2180   return 0;
2181 }
2182 
generateContainingElements(int numTargetLocations,const double * targetLocations,int ** elements,int useClosestElementIfOutside,int verbose) const2183 int VolumetricMesh::generateContainingElements(int numTargetLocations, const double * targetLocations, int ** elements, int useClosestElementIfOutside, int verbose) const
2184 {
2185   int numExternalVertices = 0;
2186 
2187   (*elements) = (int*) malloc (sizeof(int) * numTargetLocations);
2188 
2189   // determine containing (or closest) elements
2190   for (int i=0; i < numTargetLocations; i++) // over all interpolation locations
2191   {
2192     Vec3d pos = Vec3d(targetLocations[3*i+0], targetLocations[3*i+1], targetLocations[3*i+2]);
2193 
2194     // find element containing pos
2195     int element = getContainingElement(pos);
2196 
2197     // use closest element if outside
2198     if (useClosestElementIfOutside && (element < 0))
2199     {
2200       element = getClosestElement(pos);
2201       numExternalVertices++;
2202     }
2203 
2204     (*elements)[i] = element;
2205   }
2206 
2207   return numExternalVertices;
2208 }
2209 
generateInterpolationWeights(int numTargetLocations,const double * targetLocations,int ** vertices_,double ** weights,double zeroThreshold,int ** containingElements,int verbose) const2210 int VolumetricMesh::generateInterpolationWeights(int numTargetLocations, const double * targetLocations, int ** vertices_, double ** weights, double zeroThreshold, int ** containingElements, int verbose) const
2211 {
2212   int * elements = NULL;
2213 
2214   int useClosestElementIfOutside = 1;
2215   int numExternalVertices = generateContainingElements(numTargetLocations, targetLocations, &elements, useClosestElementIfOutside);
2216 
2217   // allocate interpolation arrays
2218   *vertices_ = (int*) malloc (sizeof(int) * numElementVertices * numTargetLocations);
2219   *weights = (double*) malloc (sizeof(double) * numElementVertices * numTargetLocations);
2220   int code = generateInterpolationWeights(numTargetLocations, targetLocations, elements, vertices_, weights, zeroThreshold, verbose);
2221 
2222   if (containingElements == NULL)
2223     free(elements);
2224   else
2225     *containingElements = elements;
2226 
2227   return (code == 0) ? numExternalVertices : -1;
2228 }
2229 
getNumInterpolationElementVertices(const char * filename)2230 int VolumetricMesh::getNumInterpolationElementVertices(const char * filename)
2231 {
2232   FILE * fin = fopen(filename, "r");
2233   if (!fin)
2234   {
2235     printf("Error: unable to open file %s.\n", filename);
2236     return -1;
2237   }
2238 
2239   char s[1024];
2240   if (fgets(s, 1024, fin) == NULL)
2241   {
2242     printf("Error: incorrect first line of file %s.\n", filename);
2243     return -2;
2244   }
2245   fclose(fin);
2246 
2247   VolumetricMeshParser::beautifyLine(s, 1);
2248 
2249   int slen = strlen(s);
2250   int count = 0;
2251   for(int i=0; i<slen; i++)
2252     if (s[i] == ' ')
2253       count++;
2254 
2255   if (count % 2 == 1)
2256   {
2257     printf("Error: odd number of whitespaces in the first line of file %s.\n", filename);
2258     return -3;
2259   }
2260 
2261   return count / 2;
2262 }
2263 
loadInterpolationWeights(const char * filename,int numTargetLocations,int numElementVertices_,int ** vertices_,double ** weights)2264 int VolumetricMesh::loadInterpolationWeights(const char * filename, int numTargetLocations, int numElementVertices_, int ** vertices_, double ** weights)
2265 {
2266   FILE * fin = fopen(filename, "r");
2267   if (!fin)
2268   {
2269     printf("Error: unable to open file %s.\n", filename);
2270     return 2;
2271   }
2272 
2273   // allocate interpolation arrays
2274   *vertices_ = (int*) malloc (sizeof(int) * numElementVertices_ * numTargetLocations);
2275   *weights = (double*) malloc (sizeof(double) * numElementVertices_ * numTargetLocations);
2276 
2277   int numReadTargetLocations = -1;
2278   int currentVertex;
2279 
2280   // read the elements one by one and accumulate entries
2281   while (numReadTargetLocations < numTargetLocations-1)
2282   {
2283     numReadTargetLocations++;
2284 
2285     if (feof(fin))
2286     {
2287       printf("Error: interpolation file is too short. Num vertices in interp file: %d . Should be: %d .\n", numReadTargetLocations, numTargetLocations);
2288       free(*vertices_);
2289       free(*weights);
2290       *vertices_ = NULL;
2291       *weights = NULL;
2292       fclose(fin);
2293       return 1;
2294     }
2295 
2296     if (fscanf(fin, "%d", &currentVertex) < 1)
2297       printf("Warning: bad file syntax. Unable to read interpolation info.\n");
2298 
2299     if (currentVertex != numReadTargetLocations)
2300     {
2301       printf("Error: consecutive vertex index at position %d mismatch.\n", currentVertex);
2302       free(*vertices_);
2303       free(*weights);
2304       *vertices_ = NULL;
2305       *weights = NULL;
2306       fclose(fin);
2307       return 1;
2308     }
2309 
2310     for(int j=0; j<numElementVertices_; j++)
2311     {
2312       if (fscanf(fin,"%d %lf", &((*vertices_)[currentVertex * numElementVertices_ + j]), &((*weights)[currentVertex * numElementVertices_ + j]) ) < 2)
2313         printf("Warning: bad file syntax. Unable to read interpolation info.\n");
2314     }
2315 
2316     if (fscanf(fin,"\n") < 0)
2317     {
2318       //printf("Warning: bad file syntax. Missing end of line in the interpolation file.\n");
2319       //do nothing
2320     }
2321   }
2322 
2323   fclose(fin);
2324   return 0;
2325 }
2326 
loadInterpolationWeightsBinary(const char * filename,int * numTargetLocations,int * numElementVertices_,int ** vertices_,double ** weights)2327 int VolumetricMesh::loadInterpolationWeightsBinary(const char * filename, int * numTargetLocations, int * numElementVertices_, int ** vertices_, double ** weights)
2328 {
2329   FILE * fin = fopen(filename, "rb");
2330   if (!fin)
2331   {
2332     printf("Error: unable to open file %s.\n", filename);
2333     return 2;
2334   }
2335 
2336   int code = loadInterpolationWeightsBinary(fin, numTargetLocations, numElementVertices_, vertices_, weights);
2337   fclose(fin);
2338 
2339   if (code != 0)
2340     printf("Error reading from file %s.\n", filename);
2341 
2342   return code;
2343 }
2344 
loadInterpolationWeightsBinary(FILE * fin,int * numTargetLocations,int * numElementVertices_,int ** vertices_,double ** weights)2345 int VolumetricMesh::loadInterpolationWeightsBinary(FILE * fin, int * numTargetLocations, int * numElementVertices_, int ** vertices_, double ** weights)
2346 {
2347   int buffer[2];
2348   int readItems = (int)fread(buffer, sizeof(int), 2, fin);
2349   if (readItems < 2)
2350     return 1;
2351 
2352   *numTargetLocations = buffer[0];
2353   *numElementVertices_ = buffer[1];
2354 
2355   // allocate interpolation arrays
2356   *vertices_ = (int*) malloc (sizeof(int) * *numElementVertices_ * *numTargetLocations);
2357   *weights = (double*) malloc (sizeof(double) * *numElementVertices_ * *numTargetLocations);
2358 
2359   readItems = (int)fread(*vertices_, sizeof(int), *numElementVertices_ * *numTargetLocations, fin);
2360   if (readItems < *numElementVertices_ * *numTargetLocations)
2361     return 1;
2362 
2363   readItems = (int)fread(*weights, sizeof(double), *numElementVertices_ * *numTargetLocations, fin);
2364   if (readItems < *numElementVertices_ * *numTargetLocations)
2365     return 1;
2366 
2367   return 0;
2368 }
2369 
saveInterpolationWeights(const char * filename,int numTargetLocations,int numElementVertices_,const int * vertices_,const double * weights)2370 int VolumetricMesh::saveInterpolationWeights(const char * filename, int numTargetLocations, int numElementVertices_, const int * vertices_, const double * weights)
2371 {
2372   FILE * fout = fopen(filename, "w");
2373   if (!fout)
2374   {
2375     printf("Error: unable to open file %s.\n", filename);
2376     return 1;
2377   }
2378 
2379   for(int currentVertex=0; currentVertex < numTargetLocations; currentVertex++)
2380   {
2381     fprintf(fout, "%d", currentVertex);
2382 
2383     for(int j=0; j<numElementVertices_; j++)
2384       fprintf(fout," %d %lf", vertices_[currentVertex * numElementVertices_ + j],
2385         weights[currentVertex * numElementVertices_ + j]);
2386 
2387     fprintf(fout,"\n");
2388   }
2389 
2390   fclose(fout);
2391   return 0;
2392 }
2393 
saveInterpolationWeightsBinary(const char * filename,int numTargetLocations,int numElementVertices_,const int * vertices_,const double * weights)2394 int VolumetricMesh::saveInterpolationWeightsBinary(const char * filename, int numTargetLocations, int numElementVertices_, const int * vertices_, const double * weights)
2395 {
2396   FILE * fout = fopen(filename, "wb");
2397   if (!fout)
2398   {
2399     printf("Error: unable to open file %s.\n", filename);
2400     return 1;
2401   }
2402 
2403   int code = saveInterpolationWeightsBinary(fout, numTargetLocations, numElementVertices_, vertices_, weights);
2404   fclose(fout);
2405   if (code != 0)
2406     printf("Error reading from file %s.\n", filename);
2407   return code;
2408 }
2409 
saveInterpolationWeightsBinary(FILE * fout,int numTargetLocations,int numElementVertices_,const int * vertices_,const double * weights)2410 int VolumetricMesh::saveInterpolationWeightsBinary(FILE * fout, int numTargetLocations, int numElementVertices_, const int * vertices_, const double * weights)
2411 {
2412   int buffer[2];
2413   buffer[0] = numTargetLocations;
2414   buffer[1] = numElementVertices_;
2415 
2416   int writtenItems = (int)fwrite(buffer, sizeof(int), 2, fout);
2417   if (writtenItems < 2)
2418     return 1;
2419 
2420   writtenItems = (int)fwrite(vertices_, sizeof(int), numElementVertices_ * numTargetLocations, fout);
2421   if (writtenItems < numElementVertices_ * numTargetLocations)
2422     return 1;
2423 
2424   writtenItems = (int)fwrite(weights, sizeof(double), numElementVertices_ * numTargetLocations, fout);
2425   if (writtenItems < numElementVertices_ * numTargetLocations)
2426     return 1;
2427 
2428   return 0;
2429 }
2430 
interpolate(const double * u,double * uTarget,int numTargetLocations,int numElementVertices_,const int * vertices_,const double * weights)2431 void VolumetricMesh::interpolate(const double * u, double * uTarget, int numTargetLocations, int numElementVertices_, const int * vertices_, const double * weights)
2432 {
2433   for(int i=0; i< numTargetLocations; i++)
2434   {
2435     Vec3d defo(0,0,0);
2436     for(int j=0; j<numElementVertices_; j++)
2437     {
2438       int volumetricMeshVertexIndex = vertices_[numElementVertices_ * i + j];
2439       Vec3d volumetricMeshVertexDefo = Vec3d(u[3*volumetricMeshVertexIndex+0], u[3*volumetricMeshVertexIndex+1], u[3*volumetricMeshVertexIndex+2]);
2440       defo += weights[numElementVertices_ * i + j] * volumetricMeshVertexDefo;
2441     }
2442     uTarget[3*i+0] = defo[0];
2443     uTarget[3*i+1] = defo[1];
2444     uTarget[3*i+2] = defo[2];
2445   }
2446 }
2447 
interpolateGradient(const double * U,int numFields,Vec3d pos,double * grad) const2448 int VolumetricMesh::interpolateGradient(const double * U, int numFields, Vec3d pos, double * grad) const
2449 {
2450   // find the element containing "pos"
2451   int externalVertex = 0;
2452   int element = getContainingElement(pos);
2453   if (element < 0)
2454   {
2455     element = getClosestElement(pos);
2456     externalVertex = 1;
2457   }
2458 
2459   interpolateGradient(element, U, numFields, pos, grad);
2460 
2461   return externalVertex;
2462 }
2463 
exportMeshGeometry(int * numVertices_,double ** vertices_,int * numElements_,int * numElementVertices_,int ** elements_) const2464 void VolumetricMesh::exportMeshGeometry(int * numVertices_, double ** vertices_, int * numElements_, int * numElementVertices_, int ** elements_) const
2465 {
2466   if (numVertices_ != NULL)
2467     *numVertices_ = numVertices;
2468   if (numElements_ != NULL)
2469     *numElements_ = numElements;
2470   if (numElementVertices_ != NULL)
2471     *numElementVertices_ = numElementVertices;
2472 
2473   if (vertices_ != NULL)
2474   {
2475     *vertices_ = (double*) malloc (sizeof(double) * 3 * numVertices);
2476     for(int i=0; i<numVertices; i++)
2477     {
2478       const Vec3d & v = getVertex(i);
2479       (*vertices_)[3*i+0] = v[0];
2480       (*vertices_)[3*i+1] = v[1];
2481       (*vertices_)[3*i+2] = v[2];
2482     }
2483   }
2484 
2485   if (elements_ != NULL)
2486   {
2487     *elements_ = (int*) malloc (sizeof(int) * numElementVertices * numElements);
2488     for(int i=0; i<numElements; i++)
2489     {
2490       for(int j=0; j<numElementVertices; j++)
2491         (*elements_)[numElementVertices * i + j] = elements[i][j];
2492     }
2493   }
2494 }
2495 
computeGravity(double * gravityForce,double g,bool addForce) const2496 void VolumetricMesh::computeGravity(double * gravityForce, double g, bool addForce) const
2497 {
2498   if (!addForce)
2499     memset(gravityForce, 0, sizeof(double) * 3 * numVertices);
2500 
2501   double invNumElementVertices = 1.0 / getNumElementVertices();
2502 
2503   for(int el=0; el < numElements; el++)
2504   {
2505     double volume = getElementVolume(el);
2506     double density = getElementDensity(el);
2507     double mass = density * volume;
2508     for(int j=0; j<getNumElementVertices(); j++)
2509       gravityForce[3 * getVertexIndex(el,j) + 1] -= invNumElementVertices * mass * g; // gravity assumed to act in negative y-direction
2510   }
2511 }
2512 
applyDeformation(double * u)2513 void VolumetricMesh::applyDeformation(double * u)
2514 {
2515   for(int i=0; i<numVertices; i++)
2516   {
2517     Vec3d & v = getVertex(i);
2518     v[0] += u[3*i+0];
2519     v[1] += u[3*i+1];
2520     v[2] += u[3*i+2];
2521   }
2522 }
2523 
2524 // transforms every vertex as X |--> pos + R * X
applyLinearTransformation(double * pos,double * R)2525 void VolumetricMesh::applyLinearTransformation(double * pos, double * R)
2526 {
2527   for(int i=0; i<numVertices; i++)
2528   {
2529     Vec3d & v = getVertex(i);
2530 
2531     double newPos[3];
2532     for(int j=0; j<3; j++)
2533     {
2534       newPos[j] = pos[j];
2535       for(int k=0; k<3; k++)
2536         newPos[j] += R[3*j+k] * v[k];
2537     }
2538 
2539     v[0] = newPos[0];
2540     v[1] = newPos[1];
2541     v[2] = newPos[2];
2542   }
2543 }
2544 
setMaterial(int i,const Material * material)2545 void VolumetricMesh::setMaterial(int i, const Material * material)
2546 {
2547   delete(materials[i]);
2548   materials[i] = material->clone();
2549 }
2550 
VolumetricMesh(const VolumetricMesh & volumetricMesh,int numElements_,int * elements_,map<int,int> * vertexMap_)2551 VolumetricMesh::VolumetricMesh(const VolumetricMesh & volumetricMesh, int numElements_, int * elements_, map<int,int> * vertexMap_)
2552 {
2553   // determine vertices in the submesh
2554   numElementVertices = volumetricMesh.getNumElementVertices();
2555   set<int> vertexSet;
2556   for(int i=0; i<numElements_; i++)
2557     for(int j=0; j < numElementVertices; j++)
2558       vertexSet.insert(volumetricMesh.getVertexIndex(elements_[i],j));
2559 
2560   // copy vertices into place and also into vertexMap
2561   numVertices = vertexSet.size();
2562   vertices = new Vec3d [numVertices];
2563   set<int> :: iterator iter;
2564   int vertexNo = 0;
2565   map<int, int> vertexMap;
2566   for(iter = vertexSet.begin(); iter != vertexSet.end(); iter++)
2567   {
2568     vertices[vertexNo] = volumetricMesh.getVertex(*iter);
2569     vertexMap.insert(make_pair(*iter,vertexNo));
2570     vertexNo++;
2571   }
2572 
2573   if (vertexMap_ != NULL)
2574     *vertexMap_ = vertexMap;
2575 
2576   // copy elements
2577   numElements = numElements_;
2578   elements = (int**) malloc (sizeof(int*) * numElements);
2579   elementMaterial = (int*) malloc (sizeof(int) * numElements);
2580   map<int,int> elementMap;
2581   for(int i=0; i<numElements; i++)
2582   {
2583     elements[i] = (int*) malloc (sizeof(int) * numElementVertices);
2584     for(int j=0; j< numElementVertices; j++)
2585     {
2586       map<int,int> :: iterator iter2 = vertexMap.find((volumetricMesh.elements)[elements_[i]][j]);
2587       if (iter2 == vertexMap.end())
2588       {
2589         printf("Internal error 1.\n");
2590         throw 1;
2591       }
2592       elements[i][j] = iter2->second;
2593     }
2594 
2595     elementMaterial[i] = (volumetricMesh.elementMaterial)[elements_[i]];
2596     elementMap.insert(make_pair(elements_[i], i));
2597   }
2598 
2599   // copy materials
2600   numMaterials = volumetricMesh.getNumMaterials();
2601   numSets = volumetricMesh.getNumSets();
2602   numRegions = volumetricMesh.getNumRegions();
2603 
2604   materials = (Material**) malloc (sizeof(Material*) * numMaterials);
2605   for(int i=0; i < numMaterials; i++)
2606     materials[i] = volumetricMesh.getMaterial(i)->clone();
2607 
2608   // copy element sets; restrict element sets to the new mesh, also rename vertices to reflect new vertex indices
2609   vector<Set*> newSets;
2610   map<int,int> oldToNewSetIndex;
2611   for(int oldSetIndex=0; oldSetIndex < volumetricMesh.getNumSets(); oldSetIndex++)
2612   {
2613     const Set * oldSet = volumetricMesh.getSet(oldSetIndex);
2614     set<int> oldElements;
2615     oldSet->getElements(oldElements);
2616 
2617     for(set<int> :: iterator iter = oldElements.begin(); iter != oldElements.end(); iter++)
2618     {
2619       if (*iter < 0)
2620       {
2621         printf("Internal error 2.\n");
2622         exit(1);
2623       }
2624     }
2625 
2626     // construct the element list
2627     vector<int> newElements;
2628     for(set<int> :: iterator iter = oldElements.begin(); iter != oldElements.end(); iter++)
2629     {
2630       map<int,int> :: iterator iter2 = elementMap.find(*iter);
2631       if (iter2 != elementMap.end())
2632         newElements.push_back(iter2->second);
2633     }
2634 
2635     // if there is at least one element in the new set, create a set for it
2636     if (newElements.size() > 0)
2637     {
2638       Set * newSet = new Set(oldSet->getName());
2639       for(unsigned int j=0; j<newElements.size(); j++)
2640       {
2641         if (newElements[j] < 0)
2642         {
2643           printf("Internal error 3.\n");
2644           exit(1);
2645         }
2646         newSet->insert(newElements[j]);
2647       }
2648       newSets.push_back(newSet);
2649       oldToNewSetIndex.insert(make_pair(oldSetIndex, newSets.size() - 1));
2650     }
2651   }
2652 
2653   numSets = newSets.size();
2654   sets = (Set**) malloc (sizeof(Set*) * numSets);
2655   for(int i=0; i<numSets; i++)
2656     sets[i] = newSets[i];
2657 
2658   //printf("numSets: %d\n", numSets);
2659 
2660   // copy regions; remove empty ones
2661   vector<Region*> vregions;
2662   for(int i=0; i < numRegions; i++)
2663   {
2664     const Region * sregion = volumetricMesh.getRegion(i);
2665     map<int,int> :: iterator iter = oldToNewSetIndex.find(sregion->getSetIndex());
2666     if (iter != oldToNewSetIndex.end())
2667     {
2668       Region * newRegion = new Region(sregion->getMaterialIndex(),iter->second);
2669       vregions.push_back(newRegion);
2670     }
2671   }
2672 
2673   numRegions = vregions.size();
2674   regions = (Region**) malloc (sizeof(Region*) * numRegions);
2675   for(int j=0; j<numRegions; j++)
2676     regions[j] = vregions[j];
2677 
2678   // sanity check
2679   // seek each element in all the regions
2680   for(int el=0; el<numElements; el++)
2681   {
2682     int found = 0;
2683     for(int region=0; region < numRegions; region++)
2684     {
2685       int elementSet = (regions[region])->getSetIndex();
2686 
2687       // seek for element in elementSet
2688       if (sets[elementSet]->isMember(el))
2689       {
2690         if (found != 0)
2691           printf("Warning: element %d (1-indexed) is in more than one region.\n",el+1);
2692         else
2693           found = 1;
2694       }
2695     }
2696     if (found == 0)
2697       printf("Warning: element %d (1-indexed) is not in any of the regions.\n",el+1);
2698   }
2699 
2700   // sanity check: make sure all elements are between bounds
2701   for(int i=0; i < numSets; i++)
2702   {
2703     set<int> elts;
2704     sets[i]->getElements(elts);
2705     for(set<int> :: iterator iter = elts.begin(); iter != elts.end(); iter++)
2706     {
2707       if (*iter < 0)
2708         printf("Warning: encountered negative element index in element set %d.\n",i);
2709       if (*iter >= numElements)
2710         printf("Warning: encountered too large element index in element set %d.\n",i);
2711     }
2712   }
2713 }
2714 
2715 // if vertexMap is non-null, it also returns a renaming datastructure: vertexMap[big mesh vertex] is the vertex index in the subset mesh
setToSubsetMesh(std::set<int> & subsetElements,int removeIsolatedVertices,std::map<int,int> * vertexMap)2716 void VolumetricMesh::setToSubsetMesh(std::set<int> & subsetElements, int removeIsolatedVertices, std::map<int,int> * vertexMap)
2717 {
2718   int numRemovedElements = 0;
2719   for(int el=0; el<numElements; el++)
2720   {
2721     if (subsetElements.find(el) == subsetElements.end())
2722     {
2723       free(elements[el]);
2724       elements[el] = NULL;
2725       numRemovedElements++;
2726     }
2727   }
2728 
2729   int head = 0;
2730   int tail = 0;
2731 
2732   int * lookupTable = (int *) malloc (sizeof(int) * numElements);
2733   for(int i=0; i<numElements; i++)
2734     lookupTable[i] = i;
2735 
2736   while (tail < numElements)
2737   {
2738     if (elements[tail] != NULL)
2739     {
2740       elements[head] = elements[tail];
2741       elementMaterial[head] = elementMaterial[tail];
2742       lookupTable[tail] = head;  // update to new index
2743       head++;
2744     }
2745     tail++;
2746   }
2747   numElements -= numRemovedElements;
2748   elements = (int**) realloc (elements, sizeof(int*) * numElements);
2749   elementMaterial = (int*) realloc (elementMaterial, sizeof(int) * numElements);
2750 
2751   for(int setIndex=0; setIndex < numSets; setIndex++)
2752   {
2753     set<int> setElements;
2754     sets[setIndex]->getElements(setElements);
2755     sets[setIndex]->clear();
2756     for(set<int>::iterator iter = setElements.begin(); iter != setElements.end(); iter++)
2757     {
2758       if (subsetElements.find(*iter) == subsetElements.end()) // not found!!
2759         continue;
2760       int newIndex = lookupTable[(*iter)];
2761       sets[setIndex]->insert(newIndex);
2762     }
2763   }
2764   free(lookupTable);
2765 
2766   if (removeIsolatedVertices)
2767   {
2768     set<int> retainedVertices;
2769     for(int el=0; el<numElements; el++)
2770       for(int j=0; j < numElementVertices; j++)
2771         retainedVertices.insert(getVertexIndex(el,j));
2772 
2773     int head = 0;
2774     int tail = 0;
2775 
2776     int * renamingFunction = (int*) malloc (sizeof(int) * numVertices);
2777     Vec3d * newVertices = new Vec3d [retainedVertices.size()];
2778     if (vertexMap != NULL)
2779       vertexMap->clear();
2780     while (tail < numVertices)
2781     {
2782       if (retainedVertices.find(tail) != retainedVertices.end())
2783       {
2784         renamingFunction[tail] = head;
2785         if (vertexMap != NULL)
2786           vertexMap->insert(make_pair(tail, head));
2787         newVertices[head] = vertices[tail];
2788         head++;
2789       }
2790       tail++;
2791     }
2792     assert(head == int(retainedVertices.size()));
2793 
2794     // rename vertices inside the elements
2795     for(int el=0; el<numElements; el++)
2796       for(int j=0; j < numElementVertices; j++)
2797         elements[el][j] = renamingFunction[getVertexIndex(el,j)];
2798 
2799     free(renamingFunction);
2800     numVertices = retainedVertices.size();
2801     delete [] vertices;
2802     vertices = newVertices;
2803   }
2804 }
2805 
exportToEle(const char * baseFilename,int includeRegions) const2806 int VolumetricMesh::exportToEle(const char * baseFilename, int includeRegions) const
2807 {
2808   char s[1024];
2809   sprintf(s, "%s.ele", baseFilename);
2810 
2811   FILE * fout = fopen(s, "w");
2812   if (!fout)
2813   {
2814     printf("Error: could not write to %s.\n",s);
2815     return 1;
2816   }
2817 
2818   int * elementRegion = NULL;
2819   if (includeRegions)
2820   {
2821     elementRegion = (int*) malloc (sizeof(int) * getNumElements());
2822     for(int el=0; el<getNumElements(); el++)
2823     {
2824       int found = 0;
2825       for(int region=0; region < numRegions; region++)
2826       {
2827         int elementSet = (regions[region])->getSetIndex();
2828 
2829         // seek for element in elementSet
2830         if (sets[elementSet]->isMember(el))
2831         {
2832           if (found != 0)
2833             printf("Warning: element %d (1-indexed) is in more than one region.\n",el+1);
2834           else
2835             found = region+1;
2836         }
2837       }
2838       if (found == 0)
2839         printf("Warning: element %d (1-indexed) is not in any of the regions.\n",el+1);
2840       elementRegion[el] = found;
2841     }
2842   }
2843 
2844   if (includeRegions)
2845     fprintf(fout,"%d %d %d\n", numElements, numElementVertices, 1);
2846   else
2847     fprintf(fout,"%d %d %d\n", numElements, numElementVertices, 0);
2848 
2849   for(int el=0; el < numElements; el++)
2850   {
2851     fprintf(fout,"%d ",el+1);
2852     for(int j=0; j < numElementVertices; j++)
2853     {
2854       fprintf(fout,"%d", getVertexIndex(el,j)+1);
2855       if (j != numElementVertices - 1)
2856         fprintf(fout," ");
2857     }
2858     if (includeRegions)
2859     {
2860       fprintf(fout," %d", elementRegion[el]);
2861     }
2862     fprintf(fout,"\n");
2863   }
2864 
2865   fprintf(fout,"# generated by the volumetricMesh class\n");
2866 
2867   fclose(fout);
2868 
2869   if (includeRegions)
2870     free(elementRegion);
2871 
2872   sprintf(s, "%s.node", baseFilename);
2873 
2874   fout = fopen(s, "w");
2875   if (!fout)
2876   {
2877     printf("Error: could not write to %s.\n",s);
2878     return 1;
2879   }
2880 
2881   fprintf(fout,"%d %d %d %d\n", numVertices, 3, 0, 0);
2882   for(int v=0; v < numVertices; v++)
2883   {
2884     fprintf(fout,"%d ",v+1);
2885     const Vec3d & vtx = getVertex(v);
2886     fprintf(fout,"%.15f %.15f %.15f\n", vtx[0], vtx[1], vtx[2]);
2887   }
2888 
2889   fprintf(fout,"# generated by the volumetricMesh class\n");
2890 
2891   fclose(fout);
2892 
2893   return 0;
2894 }
2895 
renumberVertices(const vector<int> & permutation)2896 void VolumetricMesh::renumberVertices(const vector<int> & permutation)
2897 {
2898 
2899   // renumber vertices
2900   Vec3d * newVertices = new Vec3d [numVertices];
2901   for (int i = 0; i < numVertices; i++)
2902     newVertices[permutation[i]] = vertices[i];
2903   delete [] vertices;
2904   vertices = newVertices;
2905 
2906   // renumber tets
2907   for (int i = 0; i < numElements; i++)
2908     for (int j = 0; j < numElementVertices; j++)
2909       elements[i][j] = permutation[elements[i][j]];
2910 }
2911 
addMaterial(const Material * material,const Set & newSet,bool removeEmptySets,bool removeEmptyMaterials)2912 void VolumetricMesh::addMaterial(const Material * material, const Set & newSet, bool removeEmptySets, bool removeEmptyMaterials)
2913 {
2914   // add new material to materials
2915   numMaterials++;
2916   materials = (Material**) realloc (materials, sizeof(Material*) * numMaterials);
2917   materials[numMaterials - 1] = material->clone();
2918 
2919   // remove indices in the sets that belong to the newSet
2920   const set<int> & newElements = newSet.getElements();
2921   for(int i = 0; i < numSets; i++)
2922   {
2923     set<int> & s = sets[i]->getElements();
2924     // skip allElements
2925     if (sets[i]->getName() == "allElements" && sets[i]->getNumElements() == numElements)
2926       continue;
2927     for(set<int>::iterator it = s.begin(); it != s.end(); )
2928     {
2929       int ele = *it;
2930       if (newElements.find(ele) != newElements.end())
2931       {
2932         set<int>::iterator it2 = it;
2933         it++;
2934         s.erase(it2);
2935       }
2936       else
2937         it++;
2938     }
2939   }
2940 
2941   // add the new Set
2942   numSets++;
2943   sets = (Set**) realloc(sets, sizeof(Set *) * numSets);
2944   sets[numSets-1] = new Set(newSet);
2945 
2946   // create a new Region
2947   numRegions++;
2948   regions = (Region**) realloc (regions, sizeof(Region*) * numRegions);
2949   regions[numRegions - 1] = new Region(numMaterials - 1, numSets - 1);
2950 
2951   // modify elementMaterial
2952   for(set<int>::const_iterator it = newElements.begin(); it != newElements.end(); it++)
2953   {
2954     int el = *it;
2955     assert(el >= 0 && el < numElements);
2956     elementMaterial[el] = numMaterials-1;
2957   }
2958 
2959   if (removeEmptySets)
2960   {
2961     bool hasEmptySet = false;
2962     vector<int> setIndexChange(numSets, 0); // old set index -> new set index
2963     int newIndex = 0;                       // store the next available set index
2964     for(int i = 0; i < numSets; i++)
2965     {
2966       if (sets[i]->getNumElements() == 0)
2967       {
2968         setIndexChange[i] = -1; // this set will be deleted, so its new set index is -1
2969         delete sets[i];
2970         sets[i] = NULL;
2971         hasEmptySet = true;
2972       }
2973       else
2974       {
2975         setIndexChange[i] = newIndex; // this set is remained, its new index is the next available index
2976         if (newIndex != i)            // this means there's already at least one set deleted
2977         {
2978           assert(newIndex < i);
2979           sets[newIndex] = sets[i];   // assign the pointer to the current set to the location at newIndex
2980         }
2981         newIndex++;
2982       }
2983     }
2984 
2985     if (hasEmptySet)
2986     {
2987       assert(newIndex < numSets);
2988       numSets = newIndex;
2989       sets = (Set**) realloc(sets, sizeof(Set *) * numSets);
2990 
2991       int newRegionIdx = 0;
2992       for(int i = 0; i < numRegions; i++)
2993       {
2994         int oldSetIdx = regions[i]->getSetIndex();
2995         assert((size_t)oldSetIdx < setIndexChange.size());
2996         if (setIndexChange[oldSetIdx] == -1) // this set has been deleted
2997         {
2998           delete regions[i];
2999           regions[i] = NULL;
3000         }
3001         else
3002         {
3003           regions[i]->setSetIndex(setIndexChange[oldSetIdx]);
3004           if (newRegionIdx != i)
3005             regions[newRegionIdx] = regions[i];
3006           newRegionIdx++;
3007         }
3008       }
3009       numRegions = newRegionIdx;
3010       regions = (Region**) realloc (regions, sizeof(Region*) * numRegions);
3011     } // end if (hasEmptySet)
3012     else
3013     {
3014       assert(newIndex == numSets);
3015     }
3016   } // end if (removeEmptySets)
3017 
3018   // remove material
3019   if (removeEmptyMaterials)
3020   {
3021     // count #Elements for each material
3022     vector<int> elementsWithMaterial(numMaterials, 0);
3023 
3024     for(int i = 0; i < numElements; i++)
3025     {
3026       int matIdx = elementMaterial[i];
3027       assert(matIdx >= 0 && matIdx < numMaterials);
3028       elementsWithMaterial[matIdx]++;
3029     }
3030 
3031     int newMatIdx = 0;
3032     vector<int> matIndexChange(numMaterials, 0); // old material index -> new material index
3033     bool hasEmptyMat = false;
3034     for(int i = 0; i < numMaterials; i++)
3035     {
3036       if (elementsWithMaterial[i] == 0)
3037       {
3038         matIndexChange[i] = -1;
3039         delete materials[i];
3040         materials[i] = NULL;
3041         hasEmptyMat = true;
3042       }
3043       else
3044       {
3045         matIndexChange[i] = newMatIdx;
3046         if (newMatIdx != i)
3047           materials[newMatIdx] = materials[i];
3048         newMatIdx++;
3049       }
3050     }
3051 
3052     if (hasEmptyMat)
3053     {
3054       numMaterials = newMatIdx;
3055       materials = (Material**) realloc (materials, sizeof(Material*) * numMaterials);
3056 
3057       // we also need to modify and delete invalid regions
3058       bool hasInvalidRegion = false;
3059       int newRegionIdx = 0;
3060       for(int i = 0; i < numRegions; i++)
3061       {
3062         int oldMatIndex = regions[i]->getMaterialIndex();
3063         if (matIndexChange[oldMatIndex] < 0)
3064         {
3065           hasInvalidRegion = true;
3066           delete regions[i];
3067           regions[i] = NULL;
3068         }
3069         else
3070         {
3071           regions[i]->setMaterialIndex(matIndexChange[oldMatIndex]);
3072           if (newRegionIdx != i)
3073             regions[newRegionIdx] = regions[i];
3074           newRegionIdx++;
3075         }
3076       }
3077 
3078       if (hasInvalidRegion)
3079       {
3080         numRegions = newRegionIdx;
3081         regions = (Region**) realloc (regions, sizeof(Region*) * numRegions);
3082       }
3083 
3084       // reassign the correct material index to each element
3085       propagateRegionsToElements();
3086     }
3087   } // end if (removeEmptyMaterials)
3088 }
3089 
3090