File: | aim/tetgen/tetgenAIM.cpp |
Warning: | line 640, column 9 Value stored to 'status' is never read |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* |
2 | * CAPS: Computational Aircraft Prototype Syntheses |
3 | * |
4 | * TetGen AIM |
5 | * |
6 | * Written by Dr. Ryan Durscher AFRL/RQVC |
7 | * |
8 | * This software has been cleared for public release on 05 Nov 2020, case number 88ABW-2020-3462. |
9 | */ |
10 | |
11 | |
12 | /*! \mainpage Introduction |
13 | * |
14 | * \section overviewTetGen TetGen AIM Overview |
15 | * A module in the Computational Aircraft Prototype Syntheses (CAPS) has been developed to interact with |
16 | * the open-source volume mesh generator, TetGen \cite Hang2015. TetGen is capable of generating exact constrained |
17 | * Delaunay tetrahedralizations, boundary conforming Delaunay meshes, and Voronoi partitions. |
18 | * |
19 | * An outline of the AIM's inputs and outputs are provided in \ref aimInputsTetGen and \ref aimOutputsTetGen, respectively. |
20 | * |
21 | * Current issues include: |
22 | * - The holes or seed points provided to TetGen by creating an taking the cnetroid of a tetrahedron from an 'empty' mesh. |
23 | * This is guaranteed to work with solid bodies, but sheet bodies with multiple segregated regions where some |
24 | * regions are holes require manual seed points to indicate the hole. |
25 | * - (<b>Important</b>) If Tetgen is allowed to added Steiner points (see "Preserve_Surf_Mesh" in \ref aimInputsTetGen) |
26 | * discrete data transfer will <b>NOT</b> be possible. |
27 | * |
28 | * \section tetgenInterface TetGen Interface |
29 | * In order to use TetGen, CAPS will automatically build the TetGen source code supplied in "library" mode. The directory |
30 | * in which the source code exists is set in the ESP configuration script. The C++ API is interfaced within the AIM |
31 | * through an interface function that takes the body tessellation and transfers the data to a "tetgenio" object |
32 | * in PLCs format (Piecewise Linear Complexes). After volume meshing is complete the mesh can be output in various |
33 | * mesh formats (see \ref aimInputsTetGen for additional details). |
34 | * |
35 | * \section clearanceTetgen Clearance Statement |
36 | * This software has been cleared for public release on 05 Nov 2020, case number 88ABW-2020-3462. |
37 | */ |
38 | |
39 | #include <string.h> |
40 | #include <math.h> |
41 | #include "capsTypes.h" |
42 | #include "aimUtil.h" |
43 | #include "aimMesh.h" |
44 | |
45 | #include "meshUtils.h" // Collection of helper functions for meshing |
46 | #include "miscUtils.h" |
47 | #include "deprecateUtils.h" |
48 | |
49 | #include "tetgen_Interface.hpp" // Bring in TetGen 'interface' function |
50 | |
51 | #ifdef WIN32 |
52 | #define snprintf _snprintf |
53 | #define strcasecmp stricmp |
54 | #endif |
55 | |
56 | //#define DEBUG |
57 | |
58 | |
59 | enum aimInputs |
60 | { |
61 | Proj_Name = 1, /* index is 1-based */ |
62 | Preserve_Surf_Mesh, |
63 | Mesh_Verbose_Flag, |
64 | Mesh_Quiet_Flag, |
65 | Quality_Rad_Edge, |
66 | Quality_Angle, |
67 | Mesh_Format, |
68 | Mesh_ASCII_Flag, |
69 | Mesh_Gen_Input_String, |
70 | Ignore_Surface_Mesh_Extraction, |
71 | Mesh_Tolerance, |
72 | Multiple_Mesh, |
73 | Regions, |
74 | Holes, |
75 | Surface_Mesh, |
76 | NUMINPUT = Surface_Mesh /* Total number of inputs */ |
77 | }; |
78 | |
79 | enum aimOutputs |
80 | { |
81 | NumberOfElement = 1, /* index is 1-based */ |
82 | NumberOfNode, |
83 | Volume_Mesh, |
84 | NUMOUT = Volume_Mesh /* Total number of outputs */ |
85 | }; |
86 | |
87 | #define NODATATRANSFER"noDataTransfer.%d" "noDataTransfer.%d" |
88 | |
89 | |
90 | typedef struct { |
91 | |
92 | // Container for mesh input |
93 | meshInputStruct meshInput; |
94 | |
95 | // Attribute to index map |
96 | mapAttrToIndexStruct attrMap; |
97 | |
98 | // Mesh references for link |
99 | int numMeshRef; |
100 | aimMeshRef *meshRef; |
101 | |
102 | } aimStorage; |
103 | |
104 | |
105 | |
106 | static int destroy_aimStorage(aimStorage *tetgenInstance) |
107 | { |
108 | |
109 | int i; // Indexing |
110 | |
111 | int status; // Function return status |
112 | |
113 | // Destroy meshInput |
114 | status = destroy_meshInputStruct(&tetgenInstance->meshInput); |
115 | if (status != CAPS_SUCCESS0) |
116 | printf("Status = %d, tetgenAIM meshInput cleanup!!!\n", status); |
117 | |
118 | // Destroy attribute to index map |
119 | status = destroy_mapAttrToIndexStruct(&tetgenInstance->attrMap); |
120 | if (status != CAPS_SUCCESS0) |
121 | printf("Status = %d, tetgenAIM attrMap cleanup!!!\n", status); |
122 | |
123 | // Free the meshRef |
124 | for (i = 0; i < tetgenInstance->numMeshRef; i++) |
125 | aim_freeMeshRef(&tetgenInstance->meshRef[i]); |
126 | AIM_FREE(tetgenInstance->meshRef){ EG_free(tetgenInstance->meshRef); tetgenInstance->meshRef = __null; }; |
127 | |
128 | return CAPS_SUCCESS0; |
129 | } |
130 | |
131 | |
132 | |
133 | /* ********************** Exposed AIM Functions ***************************** */ |
134 | |
135 | extern "C" int |
136 | aimInitialize(int inst, /*@unused@*/ const char *unitSys, void *aimInfo, |
137 | /*@unused@*/ void **instStore, /*@unused@*/ int *major, |
138 | /*@unused@*/ int *minor, int *nIn, int *nOut, |
139 | int *nFields, char ***fnames, int **franks, int **fInOut) |
140 | { |
141 | int status = CAPS_SUCCESS0; // Function status return |
142 | |
143 | aimStorage *tetgenInstance = NULL__null; |
144 | |
145 | #ifdef DEBUG |
146 | printf("\n tetgenAIM/aimInitialize instance = %d!\n", inst); |
147 | #endif |
148 | |
149 | /* specify the number of analysis input and out "parameters" */ |
150 | *nIn = NUMINPUT; |
151 | *nOut = NUMOUT; |
152 | if (inst == -1) return CAPS_SUCCESS0; |
153 | |
154 | /* specify the field variables this analysis can generate and consume */ |
155 | *nFields = 0; |
156 | *fnames = NULL__null; |
157 | *franks = NULL__null; |
158 | *fInOut = NULL__null; |
159 | |
160 | // Allocate tetgenInstance |
161 | AIM_ALLOC(tetgenInstance, 1, aimStorage, aimInfo, status){ if (tetgenInstance != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 161, __func__, 1, "AIM_ALLOC: %s != NULL" , "tetgenInstance"); goto cleanup; } size_t memorysize = 1; tetgenInstance = (aimStorage *) EG_alloc(memorysize*sizeof(aimStorage)); if (tetgenInstance == __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 161, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tetgenInstance", memorysize, "aimStorage"); goto cleanup; } }; |
162 | *instStore = tetgenInstance; |
163 | |
164 | // Set initial values for tetgenInstance // |
165 | |
166 | // Mesh reference passed to solver |
167 | tetgenInstance->numMeshRef = 0; |
168 | tetgenInstance->meshRef = NULL__null; |
169 | |
170 | // Container for attribute to index map |
171 | status = initiate_mapAttrToIndexStruct(&tetgenInstance->attrMap); |
172 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 172, __func__, 0); goto cleanup; }; |
173 | |
174 | // Container for mesh input |
175 | status = initiate_meshInputStruct(&tetgenInstance->meshInput); |
176 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 176, __func__, 0); goto cleanup; }; |
177 | |
178 | |
179 | cleanup: |
180 | if (status != CAPS_SUCCESS0) AIM_FREE(*instStore){ EG_free(*instStore); *instStore = __null; }; |
181 | return CAPS_SUCCESS0; |
182 | } |
183 | |
184 | |
185 | extern "C" int |
186 | aimInputs(/*@unused@*/ void *instStore, /*@unused@*/ void *aimInfo, int index, |
187 | char **ainame, capsValue *defval) |
188 | { |
189 | /*! \page aimInputsTetGen AIM Inputs |
190 | * The following list outlines the TetGen meshing options along with their default value available |
191 | * through the AIM interface. |
192 | */ |
193 | int status = CAPS_SUCCESS0; |
194 | |
195 | #ifdef DEBUG |
196 | printf(" tetgenAIM/aimInputs index = %d!\n", index); |
197 | #endif |
198 | |
199 | // Meshing Inputs |
200 | if (index == Proj_Name) { |
201 | *ainame = EG_strdup("Proj_Name"); // If NULL a volume grid won't be written by the AIM |
202 | defval->type = String; |
203 | defval->nullVal = IsNull; |
204 | defval->vals.string = NULL__null; |
205 | //defval->vals.string = EG_strdup("CAPS"); |
206 | defval->lfixed = Change; |
207 | |
208 | /*! \page aimInputsTetGen |
209 | * - <B> Proj_Name = NULL</B> <br> |
210 | * This corresponds to the output name of the mesh. If left NULL, the mesh is not written to a file. |
211 | */ |
212 | |
213 | } else if (index == Preserve_Surf_Mesh) { |
214 | *ainame = EG_strdup("Preserve_Surf_Mesh"); |
215 | defval->type = Boolean; |
216 | defval->vals.integer = true; |
217 | |
218 | /*! \page aimInputsTetGen |
219 | * - <B> Preserve_Surf_Mesh = True</B> <br> |
220 | * Tells TetGen to preserve the surface mesh provided (i.e. do not add Steiner points on the surface). Discrete data transfer |
221 | * will <b>NOT</b> be possible if Steiner points are added. |
222 | */ |
223 | } else if (index == Mesh_Verbose_Flag) { |
224 | *ainame = EG_strdup("Mesh_Verbose_Flag"); |
225 | defval->type = Boolean; |
226 | defval->vals.integer = false; |
227 | |
228 | /*! \page aimInputsTetGen |
229 | * - <B> Mesh_Verbose_Flag = False</B> <br> |
230 | * Verbose output from TetGen. |
231 | */ |
232 | } else if (index == Mesh_Quiet_Flag) { |
233 | *ainame = EG_strdup("Mesh_Quiet_Flag"); |
234 | defval->type = Boolean; |
235 | defval->vals.integer = false; |
236 | |
237 | /*! \page aimInputsTetGen |
238 | * - <B> Mesh_Quiet_Flag = False</B> <br> |
239 | * Complete suppression of all TetGen output messages (not including errors). |
240 | */ |
241 | } else if (index == Quality_Rad_Edge) { |
242 | *ainame = EG_strdup("Quality_Rad_Edge"); // TetGen specific parameters |
243 | defval->type = Double; |
244 | defval->vals.real = 1.5; |
245 | |
246 | /*! \page aimInputsTetGen |
247 | * - <B> Quality_Rad_Edge = 1.5</B> <br> |
248 | * TetGen maximum radius-edge ratio. |
249 | */ |
250 | } else if (index == Quality_Angle) { |
251 | *ainame = EG_strdup("Quality_Angle"); // TetGen specific parameters |
252 | defval->type = Double; |
253 | defval->vals.real = 0.0; |
254 | |
255 | /*! \page aimInputsTetGen |
256 | * - <B> Quality_Angle = 0.0</B> <br> |
257 | * TetGen minimum dihedral angle (in degrees). |
258 | */ |
259 | } else if (index == Mesh_Format) { |
260 | *ainame = EG_strdup("Mesh_Format"); |
261 | defval->type = String; |
262 | defval->vals.string = EG_strdup("AFLR3"); // TECPLOT, VTK, AFLR3, SU2, NASTRAN |
263 | defval->lfixed = Change; |
264 | |
265 | /*! \page aimInputsTetGen |
266 | * - <B> Mesh_Format = "AFLR3"</B> <br> |
267 | * Mesh output format. Available format names include: "AFLR3", "TECPLOT", "SU2", "VTK", and "NASTRAN". |
268 | */ |
269 | } else if (index == Mesh_ASCII_Flag) { |
270 | *ainame = EG_strdup("Mesh_ASCII_Flag"); |
271 | defval->type = Boolean; |
272 | defval->vals.integer = true; |
273 | |
274 | /*! \page aimInputsTetGen |
275 | * - <B> Mesh_ASCII_Flag = True</B> <br> |
276 | * Output mesh in ASCII format, otherwise write a binary file if applicable. |
277 | */ |
278 | } else if (index == Mesh_Gen_Input_String) { |
279 | *ainame = EG_strdup("Mesh_Gen_Input_String"); |
280 | defval->type = String; |
281 | defval->nullVal = IsNull; |
282 | defval->vals.string = NULL__null; |
283 | defval->lfixed = Change; |
284 | |
285 | /*! \page aimInputsTetGen |
286 | * - <B> Mesh_Gen_Input_String = NULL</B> <br> |
287 | * Meshing program command line string (as if called in bash mode). Use this to specify more |
288 | * complicated options/use features of the mesher not currently exposed through other AIM input |
289 | * variables. Note that this is the exact string that will be provided to the volume mesher; no |
290 | * modifications will be made. If left NULL an input string will be created based on default values |
291 | * of the relevant AIM input variables. See \ref tetgenCommandLineInput for options to include |
292 | * in the input string. |
293 | */ |
294 | } else if (index == Ignore_Surface_Mesh_Extraction) { // Deprecated |
295 | *ainame = EG_strdup("Ignore_Surface_Mesh_Extraction"); |
296 | defval->type = Boolean; |
297 | defval->vals.integer = true; |
298 | |
299 | // /*! \page aimInputsTetGen |
300 | // * - <B> Ignore_Surface_Mesh_Extraction = True</B> <br> |
301 | // * If TetGen doesn't preserve the surface mesh provided (i.e. Steiner points are added) a simple search algorithm may be |
302 | // * used to reconstruct a separate (not dependent on the volume mesh node numbering) representation of the surface mesh. In |
303 | // * general, this has little use and can add a significant computational penalty. The default value of "True" is recommended. |
304 | // */ |
305 | } else if (index == Mesh_Tolerance) { |
306 | *ainame = EG_strdup("Mesh_Tolerance"); // TetGen specific parameters |
307 | defval->type = Double; |
308 | defval->vals.real = 1E-16; |
309 | |
310 | /*! \page aimInputsTetGen |
311 | * - <B> Mesh_Tolerance = 1E-16</B> <br> |
312 | * Sets the tolerance for coplanar test in TetGen. |
313 | */ |
314 | } else if (index == Multiple_Mesh) { |
315 | *ainame = EG_strdup("Multiple_Mesh"); |
316 | defval->type = Boolean; |
317 | defval->vals.integer = (int) false; |
318 | |
319 | /*! \page aimInputsTetGen |
320 | * - <B> Multiple_Mesh = False</B> <br> |
321 | * If set to True a volume will be generated for each body. When set to False (default value) only a single volume |
322 | * mesh will be created. |
323 | */ |
324 | |
325 | } else if (index == Regions) { |
326 | *ainame = EG_strdup("Regions"); |
327 | defval->type = Tuple; |
328 | defval->nullVal = IsNull; |
329 | defval->dim = Vector; |
330 | defval->lfixed = Change; |
331 | defval->vals.tuple = NULL__null; |
332 | |
333 | /*! \page aimInputsTetGen |
334 | * - <B>Regions = NULL</B><br> |
335 | * If this input is set, the volume mesh will be divided into regions, |
336 | * each bounded by surface mesh and identified by an interior `seed` |
337 | * point. If a seed appears in the `Regions` input, then its region |
338 | * will be meshed and the markers for all cells in the region will be |
339 | * set to the region's `id`. The markers for cells that fall outside |
340 | * of any user-defined region or hole will be numbered automatically. |
341 | * The input is a vector of tuples. The tuple keys are ignored and the |
342 | * tuple values are dictionaries; each requires an integer `id` entry |
343 | * and a 3-vector `seed` point. For example, from within a pyCAPS |
344 | * script, |
345 | * |
346 | * \code{.py} |
347 | * tetgen.input.Regions = { |
348 | * 'A': { 'id': 10, 'seed': [0, 0, 1] }, |
349 | * 'B': { 'id': 20, 'seed': [0, 0, -1] } |
350 | * } |
351 | * \endcode |
352 | * |
353 | * Automatic hole detection will be disabled if one or both of the |
354 | * `Regions` and `Holes` inputs is not NULL. |
355 | */ |
356 | } else if (index == Holes) { |
357 | *ainame = EG_strdup("Holes"); |
358 | defval->type = Tuple; |
359 | defval->nullVal = IsNull; |
360 | defval->dim = Vector; |
361 | defval->lfixed = Change; |
362 | defval->vals.tuple = NULL__null; |
363 | |
364 | /*! \page aimInputsTetGen |
365 | * - <B>Holes = NULL</B><br> |
366 | * If this input is set, the volume mesh will be divided into regions, |
367 | * each bounded by surface mesh and identified by an interior `seed` |
368 | * point. If a seed appears in the `Holes` input, then its region will |
369 | * not be meshed. The input is a vector of tuples. The tuple keys are |
370 | * ignored and the tuple values are dictionaries; each requires a |
371 | * 3-vector `seed` point. For example, from within a pyCAPS script, |
372 | * |
373 | * \code{.py} |
374 | * tetgen.input.Holes = { |
375 | * 'A': { 'seed': [ 1, 0, 0] }, |
376 | * 'B': { 'seed': [-1, 0, 0] } |
377 | * } |
378 | * \endcode |
379 | * |
380 | * Automatic hole detection will be disabled if one or both of the |
381 | * `Regions` and `Holes` inputs is not NULL. |
382 | */ |
383 | |
384 | } else if (index == Surface_Mesh) { |
385 | *ainame = AIM_NAME(Surface_Mesh)EG_strdup("Surface_Mesh"); |
386 | defval->type = Pointer; |
387 | defval->dim = Vector; |
388 | defval->lfixed = Change; |
389 | defval->sfixed = Change; |
390 | defval->vals.AIMptr = NULL__null; |
391 | defval->nullVal = IsNull; |
392 | AIM_STRDUP(defval->units, "meshStruct", aimInfo, status){ if (defval->units != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 392, __func__, 1, "AIM_STRDUP: %s != NULL!" , "defval->units"); goto cleanup; } defval->units = EG_strdup ("meshStruct"); if (defval->units == __null) { status = -4 ; aim_status(aimInfo, status, "tetgenAIM.cpp", 392, __func__, 2, "AIM_STRDUP: %s %s", "defval->units", "meshStruct"); goto cleanup; } }; |
393 | |
394 | /*! \page aimInputsTetGen |
395 | * - <B>Surface_Mesh = NULL</B> <br> |
396 | * A Surface_Mesh link. |
397 | */ |
398 | } |
399 | |
400 | AIM_NOTNULL(*ainame, aimInfo, status){ if (*ainame == __null) { status = -307; aim_status(aimInfo, status, "tetgenAIM.cpp", 400, __func__, 1, "%s == NULL!", "*ainame" ); goto cleanup; } }; |
401 | |
402 | cleanup: |
403 | if (status != CAPS_SUCCESS0) AIM_FREE(*ainame){ EG_free(*ainame); *ainame = __null; }; |
404 | return status; |
405 | } |
406 | |
407 | |
408 | extern "C" int |
409 | aimPreAnalysis(void *instStore, void *aimInfo, capsValue *aimInputs) |
410 | { |
411 | int i, j, elem, ibody; // Indexing |
412 | |
413 | int status; // Return status |
414 | |
415 | aimStorage *tetgenInstance; |
416 | |
417 | // Incoming bodies |
418 | const char *intents; |
419 | ego *bodies = NULL__null; |
420 | int numBody = 0; |
421 | |
422 | // Container for surface mesh |
423 | int numSurfaceMesh = 0; |
424 | meshStruct *surfaceMesh = NULL__null; |
425 | |
426 | // Container for volume mesh |
427 | int numVolumeMesh = 0; |
428 | meshStruct *volumeMesh = NULL__null; |
429 | |
430 | // Meshing related variables |
431 | meshElementStruct *element; |
432 | |
433 | double box[6], boxMax[6] = {0,0,0,0,0,0}; |
434 | int bodyBoundingBox = 0; |
435 | |
436 | int numElementCheck; |
437 | |
438 | // File ouput |
439 | char *filename=NULL__null; |
440 | char bodyNumberFile[42]; |
441 | char aimFile[PATH_MAX4096]; |
442 | FILE *fp; |
443 | |
444 | // Get AIM bodies |
445 | status = aim_getBodies(aimInfo, &intents, &numBody, &bodies); |
446 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 446, __func__, 0); goto cleanup; }; |
447 | |
448 | #ifdef DEBUG |
449 | printf(" tetgenAIM/aimPreAnalysis numBody = %d!\n", numBody); |
450 | #endif |
451 | |
452 | if (numBody <= 0 || bodies == NULL__null) { |
453 | #ifdef DEBUG |
454 | printf(" tetgenAIM/aimPreAnalysis No Bodies!\n"); |
455 | #endif |
456 | return CAPS_SOURCEERR-330; |
457 | } |
458 | tetgenInstance = (aimStorage *) instStore; |
459 | |
460 | // remove previous meshes |
461 | for (ibody = 0; ibody < tetgenInstance->numMeshRef; ibody++) { |
462 | status = aim_deleteMeshes(aimInfo, &tetgenInstance->meshRef[ibody]); |
463 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 463, __func__, 0); goto cleanup; }; |
464 | } |
465 | |
466 | // Cleanup previous aimStorage for the instance in case this is the second time through preAnalysis for the same instance |
467 | status = destroy_aimStorage(tetgenInstance); |
468 | AIM_STATUS(aimInfo, status, "tetgenAIM aimStorage cleanup!!!")if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 468, __func__, 1, "tetgenAIM aimStorage cleanup!!!"); goto cleanup ; }; |
469 | |
470 | // Get capsGroup name and index mapping |
471 | status = create_CAPSGroupAttrToIndexMap(numBody, |
472 | bodies, |
473 | 2, // Only search down to the edge level of the EGADS body |
474 | &tetgenInstance->attrMap); |
475 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 475, __func__, 0); goto cleanup; }; |
476 | |
477 | // Get surface mesh |
478 | if (aimInputs[Surface_Mesh-1].nullVal == IsNull) { |
479 | AIM_ANALYSISIN_ERROR(aimInfo, Surface_Mesh, "'Surface_Mesh' input must be linked to an output 'Surface_Mesh'"){ aim_message(aimInfo, CERROR, Surface_Mesh, "tetgenAIM.cpp", 479, __func__, "'Surface_Mesh' input must be linked to an output 'Surface_Mesh'" ); }; |
480 | status = CAPS_BADVALUE-311; |
481 | goto cleanup; |
482 | } |
483 | |
484 | // Get mesh |
485 | numSurfaceMesh = aimInputs[Surface_Mesh-1].length; |
486 | surfaceMesh = (meshStruct *)aimInputs[Surface_Mesh-1].vals.AIMptr; |
487 | |
488 | if (numSurfaceMesh != numBody) { |
489 | AIM_ANALYSISIN_ERROR(aimInfo, Surface_Mesh, "Number of linked surface meshes (%d) does not match the number of bodies (%d)\n",{ aim_message(aimInfo, CERROR, Surface_Mesh, "tetgenAIM.cpp", 490, __func__, "Number of linked surface meshes (%d) does not match the number of bodies (%d)\n" , numSurfaceMesh, numBody); } |
490 | numSurfaceMesh, numBody){ aim_message(aimInfo, CERROR, Surface_Mesh, "tetgenAIM.cpp", 490, __func__, "Number of linked surface meshes (%d) does not match the number of bodies (%d)\n" , numSurfaceMesh, numBody); }; |
491 | return CAPS_SOURCEERR-330; |
492 | } |
493 | |
494 | // Create/setup volume meshes |
495 | if (aimInputs[Multiple_Mesh-1].vals.integer == (int) true) { |
496 | |
497 | AIM_ALLOC(volumeMesh, numBody, meshStruct, aimInfo, status){ if (volumeMesh != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 497, __func__, 1, "AIM_ALLOC: %s != NULL" , "volumeMesh"); goto cleanup; } size_t memorysize = numBody; volumeMesh = (meshStruct *) EG_alloc(memorysize*sizeof(meshStruct )); if (volumeMesh == __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 497, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh", memorysize, "meshStruct"); goto cleanup; } }; |
498 | numVolumeMesh = numBody; |
499 | |
500 | for (ibody = 0; ibody < numVolumeMesh; ibody++) { |
501 | status = initiate_meshStruct(&volumeMesh[ibody]); |
502 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 502, __func__, 0); goto cleanup; }; |
503 | |
504 | // Set reference mesh - One surface per body |
505 | volumeMesh[ibody].numReferenceMesh = 1; |
506 | AIM_ALLOC(volumeMesh[ibody].referenceMesh, volumeMesh[ibody].numReferenceMesh, meshStruct, aimInfo, status){ if (volumeMesh[ibody].referenceMesh != __null) { status = - 4; aim_status(aimInfo, status, "tetgenAIM.cpp", 506, __func__ , 1, "AIM_ALLOC: %s != NULL", "volumeMesh[ibody].referenceMesh" ); goto cleanup; } size_t memorysize = volumeMesh[ibody].numReferenceMesh ; volumeMesh[ibody].referenceMesh = (meshStruct *) EG_alloc(memorysize *sizeof(meshStruct)); if (volumeMesh[ibody].referenceMesh == __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 506, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "volumeMesh[ibody].referenceMesh" , memorysize, "meshStruct"); goto cleanup; } }; |
507 | |
508 | volumeMesh[ibody].referenceMesh[0] = surfaceMesh[ibody]; |
509 | printf("Tetgen MultiMesh TopoIndex = %d\n", |
510 | volumeMesh[0].referenceMesh[0].element[0].topoIndex); |
511 | } |
512 | |
513 | } else { |
514 | |
515 | // Determine which body is the bounding body based on size |
516 | bodyBoundingBox = 0; |
517 | if (numBody > 1) { |
518 | |
519 | for (ibody = 0; ibody < numBody; ibody++) { |
520 | |
521 | // Get bounding box for the body |
522 | status = EG_getBoundingBox(bodies[ibody], box); |
523 | if (status != EGADS_SUCCESS0) { |
524 | printf(" EG_getBoundingBox = %d\n\n", status); |
525 | return status; |
526 | } |
527 | |
528 | // Just copy the box coordinates on the first go around |
529 | if (ibody == 0) { |
530 | |
531 | memcpy(boxMax, box, sizeof(box)); |
532 | |
533 | // Set body as the bounding box (ie. farfield) |
534 | bodyBoundingBox = ibody; |
535 | |
536 | // Else compare with the "max" box size |
537 | } else if (boxMax[0] >= box[0] && |
538 | boxMax[1] >= box[1] && |
539 | boxMax[2] >= box[2] && |
540 | boxMax[3] <= box[3] && |
541 | boxMax[4] <= box[4] && |
542 | boxMax[5] <= box[5]) { |
543 | |
544 | // If bigger copy coordinates |
545 | memcpy(boxMax, box, sizeof(box)); |
546 | |
547 | // Set body as the bounding box (ie. farfield) |
548 | bodyBoundingBox = ibody; |
549 | } |
550 | } |
551 | } |
552 | |
553 | // Swap the surface element orientation so normals point out of the computational domain |
554 | for (ibody = 0; ibody < numBody; ibody++) { |
555 | if (ibody != bodyBoundingBox) { |
556 | // Swap two indices to reverse the normal vector of all elements on internal bodies |
557 | // so they point out of the domain |
558 | for (elem = 0; elem < surfaceMesh[ibody].numElement; elem++) { |
559 | |
560 | element = surfaceMesh[ibody].element + elem; |
561 | |
562 | // This should be valid for both Triangles and Quadrilaterals |
563 | i = element->connectivity[2]; |
564 | element->connectivity[2] = element->connectivity[0]; |
565 | element->connectivity[0] = i; |
566 | } |
567 | } |
568 | } |
569 | |
570 | numVolumeMesh = 1; |
571 | AIM_ALLOC(volumeMesh, numVolumeMesh, meshStruct, aimInfo, status){ if (volumeMesh != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 571, __func__, 1, "AIM_ALLOC: %s != NULL" , "volumeMesh"); goto cleanup; } size_t memorysize = numVolumeMesh ; volumeMesh = (meshStruct *) EG_alloc(memorysize*sizeof(meshStruct )); if (volumeMesh == __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 571, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh", memorysize, "meshStruct"); goto cleanup; } }; |
572 | |
573 | status = initiate_meshStruct(&volumeMesh[0]); |
574 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 574, __func__, 0); goto cleanup; }; |
575 | |
576 | // Combine mesh - temporary store the combined mesh in the volume mesh |
577 | status = mesh_combineMeshStruct(numSurfaceMesh, |
578 | surfaceMesh, |
579 | &volumeMesh[0]); |
580 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 580, __func__, 0); goto cleanup; }; |
581 | |
582 | // Set reference meshes - All surfaces |
583 | volumeMesh[0].numReferenceMesh = numSurfaceMesh; |
584 | AIM_ALLOC(volumeMesh[0].referenceMesh, volumeMesh[0].numReferenceMesh, meshStruct, aimInfo, status){ if (volumeMesh[0].referenceMesh != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 584, __func__, 1, "AIM_ALLOC: %s != NULL" , "volumeMesh[0].referenceMesh"); goto cleanup; } size_t memorysize = volumeMesh[0].numReferenceMesh; volumeMesh[0].referenceMesh = (meshStruct *) EG_alloc(memorysize*sizeof(meshStruct)); if (volumeMesh[0].referenceMesh == __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 584, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh[0].referenceMesh", memorysize, "meshStruct"); goto cleanup; } }; |
585 | |
586 | for (ibody = 0; ibody < numSurfaceMesh; ibody++) { |
587 | volumeMesh[0].referenceMesh[ibody] = surfaceMesh[ibody]; |
588 | } |
589 | |
590 | // Report surface mesh |
591 | printf("Number of surface nodes - %d\n", |
592 | volumeMesh[0].numNode); |
593 | printf("Number of surface elements - %d\n", |
594 | volumeMesh[0].numElement); |
595 | } |
596 | |
597 | // Setup meshing input structure - mesher specific input gets set below before entering interface |
598 | tetgenInstance->meshInput.preserveSurfMesh = aimInputs[Preserve_Surf_Mesh-1].vals.integer; |
599 | tetgenInstance->meshInput.quiet = aimInputs[Mesh_Quiet_Flag-1].vals.integer; |
600 | tetgenInstance->meshInput.outputASCIIFlag = aimInputs[Mesh_ASCII_Flag-1].vals.integer; |
601 | |
602 | AIM_STRDUP(tetgenInstance->meshInput.outputFormat, aimInputs[Mesh_Format-1].vals.string, aimInfo, status){ if (tetgenInstance->meshInput.outputFormat != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 602, __func__ , 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshInput.outputFormat" ); goto cleanup; } tetgenInstance->meshInput.outputFormat = EG_strdup(aimInputs[Mesh_Format-1].vals.string); if (tetgenInstance ->meshInput.outputFormat == __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 602, __func__, 2, "AIM_STRDUP: %s %s" , "tetgenInstance->meshInput.outputFormat", aimInputs[Mesh_Format -1].vals.string); goto cleanup; } }; |
603 | |
604 | if (aimInputs[Proj_Name-1].nullVal != IsNull) { |
605 | AIM_STRDUP(tetgenInstance->meshInput.outputFileName, aimInputs[Proj_Name-1].vals.string, aimInfo, status){ if (tetgenInstance->meshInput.outputFileName != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 605 , __func__, 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshInput.outputFileName" ); goto cleanup; } tetgenInstance->meshInput.outputFileName = EG_strdup(aimInputs[Proj_Name-1].vals.string); if (tetgenInstance ->meshInput.outputFileName == __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 605, __func__, 2, "AIM_STRDUP: %s %s" , "tetgenInstance->meshInput.outputFileName", aimInputs[Proj_Name -1].vals.string); goto cleanup; } }; |
606 | } |
607 | |
608 | // Set tetgen specific mesh inputs |
609 | tetgenInstance->meshInput.tetgenInput.meshQuality_rad_edge = aimInputs[Quality_Rad_Edge-1].vals.real; |
610 | tetgenInstance->meshInput.tetgenInput.meshQuality_angle = aimInputs[Quality_Angle-1].vals.real; |
611 | tetgenInstance->meshInput.tetgenInput.verbose = aimInputs[Mesh_Verbose_Flag-1].vals.integer; |
612 | tetgenInstance->meshInput.tetgenInput.ignoreSurfaceExtract = aimInputs[Ignore_Surface_Mesh_Extraction-1].vals.integer; |
613 | tetgenInstance->meshInput.tetgenInput.meshTolerance = aimInputs[Mesh_Tolerance-1].vals.real; |
614 | |
615 | if (aimInputs[Regions-1].nullVal != IsNull) { |
616 | populate_regions(&tetgenInstance->meshInput.tetgenInput.regions, |
617 | aimInputs[Regions-1].length, |
618 | aimInputs[Regions-1].vals.tuple); |
619 | } |
620 | if (aimInputs[Holes-1].nullVal != IsNull) { |
621 | populate_holes(&tetgenInstance->meshInput.tetgenInput.holes, |
622 | aimInputs[Holes-1].length, |
623 | aimInputs[Holes-1].vals.tuple); |
624 | } |
625 | |
626 | if (aimInputs[Mesh_Gen_Input_String-1].nullVal != IsNull) { |
627 | |
628 | AIM_STRDUP(tetgenInstance->meshInput.tetgenInput.meshInputString,{ if (tetgenInstance->meshInput.tetgenInput.meshInputString != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 629, __func__, 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshInput.tetgenInput.meshInputString" ); goto cleanup; } tetgenInstance->meshInput.tetgenInput.meshInputString = EG_strdup(aimInputs[Mesh_Gen_Input_String-1].vals.string); if (tetgenInstance->meshInput.tetgenInput.meshInputString == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 629, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshInput.tetgenInput.meshInputString" , aimInputs[Mesh_Gen_Input_String-1].vals.string); goto cleanup ; } } |
629 | aimInputs[Mesh_Gen_Input_String-1].vals.string, aimInfo, status){ if (tetgenInstance->meshInput.tetgenInput.meshInputString != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 629, __func__, 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshInput.tetgenInput.meshInputString" ); goto cleanup; } tetgenInstance->meshInput.tetgenInput.meshInputString = EG_strdup(aimInputs[Mesh_Gen_Input_String-1].vals.string); if (tetgenInstance->meshInput.tetgenInput.meshInputString == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 629, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshInput.tetgenInput.meshInputString" , aimInputs[Mesh_Gen_Input_String-1].vals.string); goto cleanup ; } }; |
630 | } |
631 | |
632 | status = populate_bndCondStruct_from_mapAttrToIndexStruct(&tetgenInstance->attrMap, |
633 | &tetgenInstance->meshInput.bndConds); |
634 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 634, __func__, 0); goto cleanup; }; |
635 | |
636 | // Call tetgen volume mesh interface |
637 | for (ibody = 0; ibody < numVolumeMesh; ibody++) { |
638 | |
639 | snprintf(bodyNumberFile, 42, "tetgen_%d", ibody); |
640 | status = aim_file(aimInfo, bodyNumberFile, aimFile); |
Value stored to 'status' is never read | |
641 | |
642 | // Call tetgen volume mesh interface for each body |
643 | if (numVolumeMesh > 1) { |
644 | printf("Getting volume mesh for body %d (of %d)\n", ibody+1, numBody); |
645 | |
646 | status = tetgen_VolumeMesh(aimInfo, |
647 | tetgenInstance->meshInput, |
648 | aimFile, |
649 | &volumeMesh[ibody].referenceMesh[0], |
650 | &volumeMesh[ibody]); |
651 | } else { |
652 | printf("Getting volume mesh\n"); |
653 | |
654 | status = tetgen_VolumeMesh(aimInfo, |
655 | tetgenInstance->meshInput, |
656 | aimFile, |
657 | &volumeMesh[ibody], |
658 | &volumeMesh[ibody]); |
659 | } |
660 | |
661 | if (status != CAPS_SUCCESS0) { |
662 | if (numVolumeMesh > 1) { |
663 | AIM_ERROR(aimInfo, "TetGen volume mesh failed on body - %d!!!!", ibody+1){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 663, __func__ , "TetGen volume mesh failed on body - %d!!!!", ibody+1); }; |
664 | } else { |
665 | AIM_ERROR(aimInfo, "TetGen volume mesh failed!!!!"){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 665, __func__ , "TetGen volume mesh failed!!!!"); }; |
666 | } |
667 | goto cleanup; |
668 | } |
669 | } |
670 | |
671 | for (i = 0; i < numVolumeMesh; i++) { |
672 | |
673 | // Check to make sure the volume mesher didn't add any unaccounted for points/faces |
674 | numElementCheck = 0; |
675 | for (j = 0; j < volumeMesh[i].numReferenceMesh; j++) { |
676 | numElementCheck += volumeMesh[i].referenceMesh[j].numElement; |
677 | } |
678 | |
679 | if (volumeMesh[i].meshQuickRef.useStartIndex == (int) false && |
680 | volumeMesh[i].meshQuickRef.useListIndex == (int) false) { |
681 | |
682 | status = mesh_retrieveNumMeshElements(volumeMesh[i].numElement, |
683 | volumeMesh[i].element, |
684 | Triangle, |
685 | &volumeMesh[i].meshQuickRef.numTriangle); |
686 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 686, __func__, 0); goto cleanup; }; |
687 | |
688 | status = mesh_retrieveNumMeshElements(volumeMesh[i].numElement, |
689 | volumeMesh[i].element, |
690 | Quadrilateral, |
691 | &volumeMesh[i].meshQuickRef.numQuadrilateral); |
692 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 692, __func__, 0); goto cleanup; }; |
693 | |
694 | } |
695 | |
696 | snprintf(bodyNumberFile, 42, NODATATRANSFER"noDataTransfer.%d", i); |
697 | status = aim_rmFile(aimInfo, bodyNumberFile); |
698 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 698, __func__, 0); goto cleanup; }; |
699 | |
700 | if (numElementCheck != volumeMesh[i].meshQuickRef.numTriangle + |
701 | volumeMesh[i].meshQuickRef.numQuadrilateral) { |
702 | |
703 | fp = aim_fopen(aimInfo, bodyNumberFile,"w"); |
704 | if (fp == NULL__null) { |
705 | AIM_ERROR(aimInfo, "Failed to open '%s'", bodyNumberFile){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 705, __func__ , "Failed to open '%s'", bodyNumberFile); }; |
706 | status = CAPS_IOERR-332; |
707 | goto cleanup; |
708 | } |
709 | fprintf(fp, "shucks..."); |
710 | fclose(fp); |
711 | |
712 | printf("Volume mesher added surface elements - data transfer will NOT be possible.\n"); |
713 | } |
714 | } |
715 | |
716 | // If filename is not NULL write the mesh |
717 | if (tetgenInstance->meshInput.outputFileName != NULL__null) { |
718 | |
719 | for (ibody = 0; ibody < numVolumeMesh; ibody++) { |
720 | |
721 | if (aimInputs[Multiple_Mesh-1].vals.integer == (int) true) { |
722 | sprintf(bodyNumberFile, "%d", ibody); |
723 | AIM_ALLOC(filename, strlen(tetgenInstance->meshInput.outputFileName) + 2 +{ if (filename != __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 724, __func__, 1, "AIM_ALLOC: %s != NULL", "filename"); goto cleanup; } size_t memorysize = strlen(tetgenInstance ->meshInput.outputFileName) + 2 + strlen("_Vol")+strlen(bodyNumberFile ); filename = (char *) EG_alloc(memorysize*sizeof(char)); if ( filename == __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 724, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "filename", memorysize, "char"); goto cleanup; } } |
724 | strlen("_Vol")+strlen(bodyNumberFile), char, aimInfo, status){ if (filename != __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 724, __func__, 1, "AIM_ALLOC: %s != NULL", "filename"); goto cleanup; } size_t memorysize = strlen(tetgenInstance ->meshInput.outputFileName) + 2 + strlen("_Vol")+strlen(bodyNumberFile ); filename = (char *) EG_alloc(memorysize*sizeof(char)); if ( filename == __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 724, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "filename", memorysize, "char"); goto cleanup; } }; |
725 | } else { |
726 | AIM_ALLOC(filename, strlen(tetgenInstance->meshInput.outputFileName)+2, char, aimInfo, status){ if (filename != __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 726, __func__, 1, "AIM_ALLOC: %s != NULL", "filename"); goto cleanup; } size_t memorysize = strlen(tetgenInstance ->meshInput.outputFileName)+2; filename = (char *) EG_alloc (memorysize*sizeof(char)); if (filename == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 726, __func__ , 3, "AIM_ALLOC: %s size %zu type %s", "filename", memorysize , "char"); goto cleanup; } }; |
727 | } |
728 | |
729 | strcpy(filename, tetgenInstance->meshInput.outputFileName); |
730 | |
731 | if (aimInputs[Multiple_Mesh-1].vals.integer == (int) true) { |
732 | strcat(filename,"_Vol"); |
733 | strcat(filename,bodyNumberFile); |
734 | } |
735 | |
736 | if (strcasecmp(tetgenInstance->meshInput.outputFormat, "AFLR3") == 0) { |
737 | |
738 | status = mesh_writeAFLR3(aimInfo, |
739 | filename, |
740 | tetgenInstance->meshInput.outputASCIIFlag, |
741 | &volumeMesh[ibody], |
742 | 1.0); |
743 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 743, __func__, 0); goto cleanup; }; |
744 | |
745 | } else if (strcasecmp(tetgenInstance->meshInput.outputFormat, "VTK") == 0) { |
746 | |
747 | status = mesh_writeVTK(aimInfo, |
748 | filename, |
749 | tetgenInstance->meshInput.outputASCIIFlag, |
750 | &volumeMesh[ibody], |
751 | 1.0); |
752 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 752, __func__, 0); goto cleanup; }; |
753 | |
754 | } else if (strcasecmp(tetgenInstance->meshInput.outputFormat, "SU2") == 0) { |
755 | |
756 | status = mesh_writeSU2(aimInfo, |
757 | filename, |
758 | tetgenInstance->meshInput.outputASCIIFlag, |
759 | &volumeMesh[ibody], |
760 | tetgenInstance->meshInput.bndConds.numBND, |
761 | tetgenInstance->meshInput.bndConds.bndID, |
762 | 1.0); |
763 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 763, __func__, 0); goto cleanup; }; |
764 | |
765 | } else if (strcasecmp(tetgenInstance->meshInput.outputFormat, "Tecplot") == 0) { |
766 | |
767 | status = mesh_writeTecplot(aimInfo, |
768 | filename, |
769 | tetgenInstance->meshInput.outputASCIIFlag, |
770 | &volumeMesh[ibody], |
771 | 1.0); |
772 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 772, __func__, 0); goto cleanup; }; |
773 | |
774 | } else if (strcasecmp(tetgenInstance->meshInput.outputFormat, "Nastran") == 0) { |
775 | |
776 | status = mesh_writeNASTRAN(aimInfo, |
777 | filename, |
778 | tetgenInstance->meshInput.outputASCIIFlag, |
779 | &volumeMesh[ibody], |
780 | LargeField, |
781 | 1.0); |
782 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 782, __func__, 0); goto cleanup; }; |
783 | |
784 | } else { |
785 | AIM_ERROR(aimInfo, "Unrecognized mesh format, \"%s\"",{ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 786, __func__ , "Unrecognized mesh format, \"%s\"", tetgenInstance->meshInput .outputFormat); } |
786 | tetgenInstance->meshInput.outputFormat){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 786, __func__ , "Unrecognized mesh format, \"%s\"", tetgenInstance->meshInput .outputFormat); }; |
787 | status = CAPS_BADVALUE-311; |
788 | goto cleanup; |
789 | } |
790 | AIM_FREE(filename){ EG_free(filename); filename = __null; }; |
791 | } |
792 | } else { |
793 | printf("No project name (\"Proj_Name\") provided - A volume mesh will not be written out\n"); |
794 | } |
795 | |
796 | status = CAPS_SUCCESS0; |
797 | |
798 | cleanup: |
799 | |
800 | // Destroy volumeMesh allocated arrays |
801 | if (volumeMesh != NULL__null) { |
802 | for (i = 0; i < numVolumeMesh; i++) { |
803 | (void) destroy_meshStruct(&volumeMesh[i]); |
804 | } |
805 | AIM_FREE(volumeMesh){ EG_free(volumeMesh); volumeMesh = __null; }; |
806 | } |
807 | AIM_FREE(filename){ EG_free(filename); filename = __null; }; |
808 | |
809 | return status; |
810 | } |
811 | |
812 | |
813 | /* the execution code from above should be moved here */ |
814 | extern "C" int |
815 | aimExecute(/*@unused@*/ void *instStore, /*@unused@*/ void *aimStruc, int *state) |
816 | { |
817 | *state = 0; |
818 | return CAPS_SUCCESS0; |
819 | } |
820 | |
821 | |
822 | /* no longer optional and needed for restart */ |
823 | extern "C" int |
824 | aimPostAnalysis(/*@unused@*/ void *instStore, /*@unused@*/ void *aimInfo, |
825 | /*@unused@*/ int restart, /*@unused@*/ capsValue *aimInputs) |
826 | { |
827 | int status = CAPS_SUCCESS0; |
828 | |
829 | // Incoming bodies |
830 | const char *intents; |
831 | ego *bodies = NULL__null; |
832 | int numBody = 0; |
833 | |
834 | // Container for volume mesh |
835 | int numSurfaceMesh=0; |
836 | meshStruct *surfaceMesh=NULL__null; |
837 | |
838 | int i, ibody, nodeOffSet; |
839 | int noDataTransfer = (int)false; |
840 | |
841 | char bodyNumberFile[42]; |
842 | char aimFile[PATH_MAX4096]; |
843 | |
844 | aimStorage *tetgenInstance; |
845 | |
846 | tetgenInstance = (aimStorage *) instStore; |
847 | |
848 | // Get AIM bodies |
849 | status = aim_getBodies(aimInfo, &intents, &numBody, &bodies); |
850 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 850, __func__, 0); goto cleanup; }; |
851 | |
852 | // Get mesh |
853 | numSurfaceMesh = aimInputs[Surface_Mesh-1].length; |
854 | surfaceMesh = (meshStruct *)aimInputs[Surface_Mesh-1].vals.AIMptr; |
855 | AIM_NOTNULL(surfaceMesh, aimInfo, status){ if (surfaceMesh == __null) { status = -307; aim_status(aimInfo , status, "tetgenAIM.cpp", 855, __func__, 1, "%s == NULL!", "surfaceMesh" ); goto cleanup; } }; |
856 | |
857 | // Create/setup volume meshes |
858 | if (aimInputs[Multiple_Mesh-1].vals.integer == (int) true) { |
859 | |
860 | AIM_ALLOC(tetgenInstance->meshRef, numBody, aimMeshRef, aimInfo, status){ if (tetgenInstance->meshRef != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 860, __func__, 1, "AIM_ALLOC: %s != NULL" , "tetgenInstance->meshRef"); goto cleanup; } size_t memorysize = numBody; tetgenInstance->meshRef = (aimMeshRef *) EG_alloc (memorysize*sizeof(aimMeshRef)); if (tetgenInstance->meshRef == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 860, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef" , memorysize, "aimMeshRef"); goto cleanup; } }; |
861 | tetgenInstance->numMeshRef = numBody; |
862 | |
863 | for (ibody = 0; ibody < numBody; ibody++) { |
864 | status = aim_initMeshRef(tetgenInstance->meshRef); |
865 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 865, __func__, 0); goto cleanup; }; |
866 | } |
867 | |
868 | for (ibody = 0; ibody < numBody; ibody++) { |
869 | snprintf(bodyNumberFile, 42, "tetgen_%d", ibody); |
870 | status = aim_file(aimInfo, bodyNumberFile, aimFile); |
871 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 871, __func__, 0); goto cleanup; }; |
872 | AIM_STRDUP(tetgenInstance->meshRef[ibody].fileName, aimFile, aimInfo, status){ if (tetgenInstance->meshRef[ibody].fileName != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 872 , __func__, 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshRef[ibody].fileName" ); goto cleanup; } tetgenInstance->meshRef[ibody].fileName = EG_strdup(aimFile); if (tetgenInstance->meshRef[ibody]. fileName == __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 872, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshRef[ibody].fileName" , aimFile); goto cleanup; } }; |
873 | |
874 | tetgenInstance->meshRef[ibody].maps[0].tess = surfaceMesh[ibody].egadsTess; |
875 | |
876 | snprintf(bodyNumberFile, 42, NODATATRANSFER"noDataTransfer.%d", ibody); |
877 | if (aim_isFile(aimInfo, bodyNumberFile) == CAPS_SUCCESS0) continue; |
878 | |
879 | tetgenInstance->meshRef[0].nmap = 1; |
880 | AIM_ALLOC(tetgenInstance->meshRef[ibody].maps[0].map, surfaceMesh[ibody].numNode, int, aimInfo, status){ if (tetgenInstance->meshRef[ibody].maps[0].map != __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 880, __func__, 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[ibody].maps[0].map" ); goto cleanup; } size_t memorysize = surfaceMesh[ibody].numNode ; tetgenInstance->meshRef[ibody].maps[0].map = (int *) EG_alloc (memorysize*sizeof(int)); if (tetgenInstance->meshRef[ibody ].maps[0].map == __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 880, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tetgenInstance->meshRef[ibody].maps[0].map", memorysize , "int"); goto cleanup; } }; |
881 | for (i = 0; i < surfaceMesh[ibody].numNode; i++) |
882 | tetgenInstance->meshRef[ibody].maps[0].map[i] = i+1; |
883 | } |
884 | |
885 | } else { |
886 | |
887 | AIM_ALLOC(tetgenInstance->meshRef, 1, aimMeshRef, aimInfo, status){ if (tetgenInstance->meshRef != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 887, __func__, 1, "AIM_ALLOC: %s != NULL" , "tetgenInstance->meshRef"); goto cleanup; } size_t memorysize = 1; tetgenInstance->meshRef = (aimMeshRef *) EG_alloc(memorysize *sizeof(aimMeshRef)); if (tetgenInstance->meshRef == __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 887, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef" , memorysize, "aimMeshRef"); goto cleanup; } }; |
888 | tetgenInstance->numMeshRef = 1; |
889 | ibody = 0; |
890 | |
891 | status = aim_initMeshRef(tetgenInstance->meshRef); |
892 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 892, __func__, 0); goto cleanup; }; |
893 | |
894 | // set the filename without extensions where the grid is written for solvers |
895 | snprintf(bodyNumberFile, 42, "tetgen_%d", ibody); |
896 | status = aim_file(aimInfo, bodyNumberFile, aimFile); |
897 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 897, __func__, 0); goto cleanup; }; |
898 | AIM_STRDUP(tetgenInstance->meshRef[0].fileName, aimFile, aimInfo, status){ if (tetgenInstance->meshRef[0].fileName != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 898, __func__ , 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshRef[0].fileName" ); goto cleanup; } tetgenInstance->meshRef[0].fileName = EG_strdup (aimFile); if (tetgenInstance->meshRef[0].fileName == __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 898, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshRef[0].fileName" , aimFile); goto cleanup; } }; |
899 | |
900 | snprintf(bodyNumberFile, 42, NODATATRANSFER"noDataTransfer.%d", ibody); |
901 | if (aim_isFile(aimInfo, bodyNumberFile) == CAPS_SUCCESS0) { |
902 | noDataTransfer = (int)true; |
903 | } |
904 | |
905 | AIM_ALLOC(tetgenInstance->meshRef[0].maps, numSurfaceMesh, aimMeshTessMap, aimInfo, status){ if (tetgenInstance->meshRef[0].maps != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 905, __func__ , 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[0].maps" ); goto cleanup; } size_t memorysize = numSurfaceMesh; tetgenInstance ->meshRef[0].maps = (aimMeshTessMap *) EG_alloc(memorysize *sizeof(aimMeshTessMap)); if (tetgenInstance->meshRef[0].maps == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 905, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef[0].maps" , memorysize, "aimMeshTessMap"); goto cleanup; } }; |
906 | tetgenInstance->meshRef[0].nmap = numSurfaceMesh; |
907 | |
908 | nodeOffSet = 0; |
909 | for (ibody = 0; ibody < numSurfaceMesh; ibody++) { |
910 | tetgenInstance->meshRef[0].maps[ibody].tess = surfaceMesh[ibody].egadsTess; |
911 | tetgenInstance->meshRef[0].maps[ibody].map = NULL__null; |
912 | |
913 | if (noDataTransfer == (int)true) continue; |
914 | |
915 | AIM_ALLOC(tetgenInstance->meshRef[0].maps[ibody].map, surfaceMesh[ibody].numNode, int, aimInfo, status){ if (tetgenInstance->meshRef[0].maps[ibody].map != __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 915, __func__, 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[0].maps[ibody].map" ); goto cleanup; } size_t memorysize = surfaceMesh[ibody].numNode ; tetgenInstance->meshRef[0].maps[ibody].map = (int *) EG_alloc (memorysize*sizeof(int)); if (tetgenInstance->meshRef[0].maps [ibody].map == __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 915, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tetgenInstance->meshRef[0].maps[ibody].map", memorysize , "int"); goto cleanup; } }; |
916 | for (i = 0; i < surfaceMesh[ibody].numNode; i++) |
917 | tetgenInstance->meshRef[0].maps[ibody].map[i] = nodeOffSet + i+1; |
918 | |
919 | nodeOffSet += surfaceMesh[ibody].numNode; |
920 | } |
921 | } |
922 | |
923 | |
924 | cleanup: |
925 | return status; |
926 | } |
927 | |
928 | |
929 | extern "C" int |
930 | aimOutputs(/*@unused@*/ void *instStore, /*@unused@*/ void *aimInfo, int index, |
931 | char **aoname, capsValue *form) |
932 | { |
933 | /*! \page aimOutputsTetGen AIM Outputs |
934 | * The following list outlines the TetGen AIM outputs available through the AIM interface. |
935 | */ |
936 | |
937 | int status = CAPS_SUCCESS0; |
938 | |
939 | #ifdef DEBUG |
940 | printf(" tetgenAIM/aimOutputs index = %d!\n", index); |
941 | #endif |
942 | if (index == NumberOfElement) { |
943 | *aoname = EG_strdup("NumberOfElement"); |
944 | form->type = Integer; |
945 | form->vals.integer = 0; |
946 | |
947 | /*! \page aimOutputsTetGen |
948 | * - <B> NumberOfElement </B> <br> |
949 | * Number of elements in the surface mesh |
950 | */ |
951 | |
952 | } else if (index == NumberOfNode) { |
953 | *aoname = EG_strdup("NumberOfNode"); |
954 | form->type = Integer; |
955 | form->vals.integer = 0; |
956 | |
957 | /*! \page aimOutputsTetGen |
958 | * - <B> NumberOfNode </B> <br> |
959 | * Number of vertices in the surface mesh |
960 | */ |
961 | |
962 | } else if (index == Volume_Mesh) { |
963 | *aoname = AIM_NAME(Volume_Mesh)EG_strdup("Volume_Mesh"); |
964 | form->type = PointerMesh; |
965 | form->dim = Vector; |
966 | form->lfixed = Change; |
967 | form->sfixed = Fixed; |
968 | form->vals.AIMptr = NULL__null; |
969 | form->nullVal = IsNull; |
970 | |
971 | /*! \page aimOutputsTetGen |
972 | * - <B> Volume_Mesh </B> <br> |
973 | * The volume mesh for a link |
974 | */ |
975 | |
976 | } else { |
977 | status = CAPS_BADINDEX-304; |
978 | AIM_STATUS(aimInfo, status, "Unknown output index %d!", index)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 978, __func__, 2, "Unknown output index %d!", index); goto cleanup ; }; |
979 | } |
980 | |
981 | AIM_NOTNULL(*aoname, aimInfo, status){ if (*aoname == __null) { status = -307; aim_status(aimInfo, status, "tetgenAIM.cpp", 981, __func__, 1, "%s == NULL!", "*aoname" ); goto cleanup; } }; |
982 | |
983 | cleanup: |
984 | if (status != CAPS_SUCCESS0) AIM_FREE(*aoname){ EG_free(*aoname); *aoname = __null; }; |
985 | return status; |
986 | } |
987 | |
988 | |
989 | extern "C" int |
990 | aimCalcOutput(void *instStore, void *aimInfo, int index, capsValue *val) |
991 | { |
992 | int i, status = CAPS_SUCCESS0; |
993 | int numElement, numNodes; |
994 | int nVertex, nTri, nQuad, nTet, nPyramid, nPrism, nHex; |
995 | aimStorage *tetgenInstance; |
996 | aimMesh mesh; |
997 | |
998 | #ifdef DEBUG |
999 | printf(" tetgenAIM/aimCalcOutput index = %d!\n", index); |
1000 | #endif |
1001 | tetgenInstance = (aimStorage *) instStore; |
1002 | |
1003 | if (NumberOfElement == index) { |
1004 | |
1005 | // Count the total number of surface elements |
1006 | numElement = 0; |
1007 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { |
1008 | status = aim_readBinaryUgridHeader(aimInfo, &tetgenInstance->meshRef[i], |
1009 | &nVertex, &nTri, &nQuad, |
1010 | &nTet, &nPyramid, &nPrism, &nHex); |
1011 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1011, __func__, 0); goto cleanup; }; |
1012 | |
1013 | numElement += nTri + nQuad + nTet + nPyramid + nPrism + nHex; |
1014 | } |
1015 | |
1016 | val->vals.integer = numElement; |
1017 | |
1018 | } else if (NumberOfNode == index) { |
1019 | |
1020 | // Count the total number of surface vertices |
1021 | numNodes = 0; |
1022 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { |
1023 | status = aim_readBinaryUgridHeader(aimInfo, &tetgenInstance->meshRef[i], |
1024 | &nVertex, &nTri, &nQuad, |
1025 | &nTet, &nPyramid, &nPrism, &nHex); |
1026 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1026, __func__, 0); goto cleanup; }; |
1027 | |
1028 | numNodes += nVertex; |
1029 | } |
1030 | |
1031 | val->vals.integer = numNodes; |
1032 | |
1033 | } else if (Volume_Mesh == index) { |
1034 | |
1035 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { |
1036 | status = aim_queryMeshes( aimInfo, Volume_Mesh, &tetgenInstance->meshRef[i] ); |
1037 | if (status > 0) { |
1038 | mesh.meshData = NULL__null; |
1039 | mesh.meshRef = &tetgenInstance->meshRef[i]; |
1040 | |
1041 | status = aim_readBinaryUgrid(aimInfo, &mesh); |
1042 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1042, __func__, 0); goto cleanup; }; |
1043 | |
1044 | status = aim_writeMeshes(aimInfo, Volume_Mesh, &mesh); |
1045 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1045, __func__, 0); goto cleanup; }; |
1046 | |
1047 | status = aim_freeMeshData(mesh.meshData); |
1048 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1048, __func__, 0); goto cleanup; }; |
1049 | AIM_FREE(mesh.meshData){ EG_free(mesh.meshData); mesh.meshData = __null; }; |
1050 | } |
1051 | else |
1052 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1052, __func__, 0); goto cleanup; }; |
1053 | } |
1054 | |
1055 | // Return the volume mesh references |
1056 | val->nrow = tetgenInstance->numMeshRef; |
1057 | val->vals.AIMptr = tetgenInstance->meshRef; |
1058 | |
1059 | } else { |
1060 | |
1061 | status = CAPS_BADINDEX-304; |
1062 | AIM_STATUS(aimInfo, status, "Unknown output index %d!", index)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1062, __func__, 2, "Unknown output index %d!", index); goto cleanup; }; |
1063 | |
1064 | } |
1065 | |
1066 | cleanup: |
1067 | |
1068 | return status; |
1069 | } |
1070 | |
1071 | extern "C" void |
1072 | aimCleanup(void *instStore) |
1073 | { |
1074 | int status; // Function return status |
1075 | aimStorage *tetgenInstance; |
1076 | |
1077 | #ifdef DEBUG |
1078 | printf(" tetgenAIM/aimCleanup!\n"); |
1079 | #endif |
1080 | tetgenInstance = (aimStorage *) instStore; |
1081 | |
1082 | status = destroy_aimStorage(tetgenInstance); |
1083 | if (status != CAPS_SUCCESS0) |
1084 | printf("Status = %d, tetgenAIM aimStorage cleanup!!!\n", status); |
1085 | |
1086 | EG_free(tetgenInstance); |
1087 | } |