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", ¤tVertex) < 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