File: | tetgenAIM.cpp |
Warning: | line 939, column 12 The left operand of '!=' is a garbage value |
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 | #define TETGENFILE"tetgen_%d" "tetgen_%d" | |||
59 | ||||
60 | enum aimInputs | |||
61 | { | |||
62 | Proj_Name = 1, /* index is 1-based */ | |||
63 | Preserve_Surf_Mesh, | |||
64 | Mesh_Verbose_Flag, | |||
65 | Mesh_Quiet_Flag, | |||
66 | Quality_Rad_Edge, | |||
67 | Quality_Angle, | |||
68 | Mesh_Format, | |||
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 groupMap; | |||
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->groupMap); | |||
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 | tetgenInstance->numMeshRef = 0; | |||
128 | ||||
129 | return CAPS_SUCCESS0; | |||
130 | } | |||
131 | ||||
132 | ||||
133 | ||||
134 | /* ********************** Exposed AIM Functions ***************************** */ | |||
135 | ||||
136 | extern "C" int | |||
137 | aimInitialize(int inst, /*@unused@*/ const char *unitSys, void *aimInfo, | |||
138 | /*@unused@*/ void **instStore, /*@unused@*/ int *major, | |||
139 | /*@unused@*/ int *minor, int *nIn, int *nOut, | |||
140 | int *nFields, char ***fnames, int **franks, int **fInOut) | |||
141 | { | |||
142 | int status = CAPS_SUCCESS0; // Function status return | |||
143 | ||||
144 | aimStorage *tetgenInstance = NULL__null; | |||
145 | ||||
146 | #ifdef DEBUG | |||
147 | printf("\n tetgenAIM/aimInitialize instance = %d!\n", inst); | |||
148 | #endif | |||
149 | ||||
150 | /* specify the number of analysis input and out "parameters" */ | |||
151 | *nIn = NUMINPUT; | |||
152 | *nOut = NUMOUT; | |||
153 | if (inst == -1) return CAPS_SUCCESS0; | |||
154 | ||||
155 | /* specify the field variables this analysis can generate and consume */ | |||
156 | *nFields = 0; | |||
157 | *fnames = NULL__null; | |||
158 | *franks = NULL__null; | |||
159 | *fInOut = NULL__null; | |||
160 | ||||
161 | // Allocate tetgenInstance | |||
162 | AIM_ALLOC(tetgenInstance, 1, aimStorage, aimInfo, status){ if (tetgenInstance != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 162, __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", 162, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tetgenInstance", memorysize, "aimStorage"); goto cleanup; } }; | |||
163 | *instStore = tetgenInstance; | |||
164 | ||||
165 | // Set initial values for tetgenInstance // | |||
166 | ||||
167 | // Mesh reference passed to solver | |||
168 | tetgenInstance->numMeshRef = 0; | |||
169 | tetgenInstance->meshRef = NULL__null; | |||
170 | ||||
171 | // Container for attribute to index map | |||
172 | status = initiate_mapAttrToIndexStruct(&tetgenInstance->groupMap); | |||
173 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 173, __func__, 0); goto cleanup; }; | |||
174 | ||||
175 | // Container for mesh input | |||
176 | status = initiate_meshInputStruct(&tetgenInstance->meshInput); | |||
177 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 177, __func__, 0); goto cleanup; }; | |||
178 | ||||
179 | ||||
180 | cleanup: | |||
181 | if (status != CAPS_SUCCESS0) AIM_FREE(*instStore){ EG_free(*instStore); *instStore = __null; }; | |||
182 | return CAPS_SUCCESS0; | |||
183 | } | |||
184 | ||||
185 | ||||
186 | extern "C" int | |||
187 | aimInputs(/*@unused@*/ void *instStore, /*@unused@*/ void *aimInfo, int index, | |||
188 | char **ainame, capsValue *defval) | |||
189 | { | |||
190 | /*! \page aimInputsTetGen AIM Inputs | |||
191 | * The following list outlines the TetGen meshing options along with their default value available | |||
192 | * through the AIM interface. | |||
193 | */ | |||
194 | int status = CAPS_SUCCESS0; | |||
195 | ||||
196 | #ifdef DEBUG | |||
197 | printf(" tetgenAIM/aimInputs index = %d!\n", index); | |||
198 | #endif | |||
199 | ||||
200 | // Meshing Inputs | |||
201 | if (index == Proj_Name) { | |||
202 | *ainame = EG_strdup("Proj_Name"); // If NULL a volume grid won't be written by the AIM | |||
203 | defval->type = String; | |||
204 | defval->nullVal = IsNull; | |||
205 | defval->vals.string = NULL__null; | |||
206 | //defval->vals.string = EG_strdup("CAPS"); | |||
207 | defval->lfixed = Change; | |||
208 | ||||
209 | /*! \page aimInputsTetGen | |||
210 | * - <B> Proj_Name = NULL</B> <br> | |||
211 | * Output name prefix for meshes to be written in formats specified by Mesh_Format. | |||
212 | * These meshes are not linked to any analysis, but may be useful exploring meshing parameters. | |||
213 | */ | |||
214 | ||||
215 | } else if (index == Mesh_Format) { | |||
216 | *ainame = EG_strdup("Mesh_Format"); | |||
217 | defval->type = String; | |||
218 | defval->vals.string = NULL__null; | |||
219 | defval->nullVal = IsNull; | |||
220 | defval->dim = Vector; | |||
221 | defval->lfixed = Change; | |||
222 | ||||
223 | /*! \page aimInputsTetGen | |||
224 | * \include{doc} Mesh_Format.dox | |||
225 | */ | |||
226 | ||||
227 | } else if (index == Preserve_Surf_Mesh) { | |||
228 | *ainame = EG_strdup("Preserve_Surf_Mesh"); | |||
229 | defval->type = Boolean; | |||
230 | defval->vals.integer = true; | |||
231 | ||||
232 | /*! \page aimInputsTetGen | |||
233 | * - <B> Preserve_Surf_Mesh = True</B> <br> | |||
234 | * Tells TetGen to preserve the surface mesh provided (i.e. do not add Steiner points on the surface). Discrete data transfer | |||
235 | * will <b>NOT</b> be possible if Steiner points are added. | |||
236 | */ | |||
237 | } else if (index == Mesh_Verbose_Flag) { | |||
238 | *ainame = EG_strdup("Mesh_Verbose_Flag"); | |||
239 | defval->type = Boolean; | |||
240 | defval->vals.integer = false; | |||
241 | ||||
242 | /*! \page aimInputsTetGen | |||
243 | * - <B> Mesh_Verbose_Flag = False</B> <br> | |||
244 | * Verbose output from TetGen. | |||
245 | */ | |||
246 | } else if (index == Mesh_Quiet_Flag) { | |||
247 | *ainame = EG_strdup("Mesh_Quiet_Flag"); | |||
248 | defval->type = Boolean; | |||
249 | defval->vals.integer = false; | |||
250 | ||||
251 | /*! \page aimInputsTetGen | |||
252 | * - <B> Mesh_Quiet_Flag = False</B> <br> | |||
253 | * Complete suppression of all TetGen output messages (not including errors). | |||
254 | */ | |||
255 | } else if (index == Quality_Rad_Edge) { | |||
256 | *ainame = EG_strdup("Quality_Rad_Edge"); // TetGen specific parameters | |||
257 | defval->type = Double; | |||
258 | defval->vals.real = 1.5; | |||
259 | ||||
260 | /*! \page aimInputsTetGen | |||
261 | * - <B> Quality_Rad_Edge = 1.5</B> <br> | |||
262 | * TetGen maximum radius-edge ratio. | |||
263 | */ | |||
264 | } else if (index == Quality_Angle) { | |||
265 | *ainame = EG_strdup("Quality_Angle"); // TetGen specific parameters | |||
266 | defval->type = Double; | |||
267 | defval->vals.real = 0.0; | |||
268 | ||||
269 | /*! \page aimInputsTetGen | |||
270 | * - <B> Quality_Angle = 0.0</B> <br> | |||
271 | * TetGen minimum dihedral angle (in degrees). | |||
272 | */ | |||
273 | ||||
274 | } else if (index == Mesh_Gen_Input_String) { | |||
275 | *ainame = EG_strdup("Mesh_Gen_Input_String"); | |||
276 | defval->type = String; | |||
277 | defval->nullVal = IsNull; | |||
278 | defval->vals.string = NULL__null; | |||
279 | defval->lfixed = Change; | |||
280 | ||||
281 | /*! \page aimInputsTetGen | |||
282 | * - <B> Mesh_Gen_Input_String = NULL</B> <br> | |||
283 | * Meshing program command line string (as if called in bash mode). Use this to specify more | |||
284 | * complicated options/use features of the mesher not currently exposed through other AIM input | |||
285 | * variables. Note that this is the exact string that will be provided to the volume mesher; no | |||
286 | * modifications will be made. If left NULL an input string will be created based on default values | |||
287 | * of the relevant AIM input variables. See \ref tetgenCommandLineInput for options to include | |||
288 | * in the input string. | |||
289 | */ | |||
290 | } else if (index == Ignore_Surface_Mesh_Extraction) { // Deprecated | |||
291 | *ainame = EG_strdup("Ignore_Surface_Mesh_Extraction"); | |||
292 | defval->type = Boolean; | |||
293 | defval->vals.integer = true; | |||
294 | ||||
295 | // /*! \page aimInputsTetGen | |||
296 | // * - <B> Ignore_Surface_Mesh_Extraction = True</B> <br> | |||
297 | // * If TetGen doesn't preserve the surface mesh provided (i.e. Steiner points are added) a simple search algorithm may be | |||
298 | // * used to reconstruct a separate (not dependent on the volume mesh node numbering) representation of the surface mesh. In | |||
299 | // * general, this has little use and can add a significant computational penalty. The default value of "True" is recommended. | |||
300 | // */ | |||
301 | } else if (index == Mesh_Tolerance) { | |||
302 | *ainame = EG_strdup("Mesh_Tolerance"); // TetGen specific parameters | |||
303 | defval->type = Double; | |||
304 | defval->vals.real = 1E-16; | |||
305 | ||||
306 | /*! \page aimInputsTetGen | |||
307 | * - <B> Mesh_Tolerance = 1E-16</B> <br> | |||
308 | * Sets the tolerance for coplanar test in TetGen. | |||
309 | */ | |||
310 | } else if (index == Multiple_Mesh) { | |||
311 | *ainame = EG_strdup("Multiple_Mesh"); | |||
312 | defval->type = String; | |||
313 | AIM_STRDUP(defval->vals.string, "SingleDomain", aimInfo, status){ if (defval->vals.string != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 313, __func__, 1, "AIM_STRDUP: %s != NULL!" , "defval->vals.string"); goto cleanup; } defval->vals. string = EG_strdup("SingleDomain"); if (defval->vals.string == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 313, __func__, 2, "AIM_STRDUP: %s %s", "defval->vals.string" , "SingleDomain"); goto cleanup; } }; | |||
314 | ||||
315 | /*! \page aimInputsTetGen | |||
316 | * - <B> Multiple_Mesh = "SingleDomain"</B> <br> | |||
317 | * If "SingleDomain": Generate a single volume mesh file is assuming multiple | |||
318 | * bodies define a single computational domain (i.e. CFD)<br> | |||
319 | * <br> | |||
320 | * If "MultiFile": Generate a volume mesh file for each body.<br> | |||
321 | * <br> | |||
322 | * If "MultiDomain": Generate a single mesh file containing multiple volume meshes for each body.<br> | |||
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 = PointerMesh; | |||
387 | defval->dim = Vector; | |||
388 | defval->lfixed = Change; | |||
389 | defval->sfixed = Fixed; | |||
390 | defval->vals.AIMptr = NULL__null; | |||
391 | defval->nullVal = IsNull; | |||
392 | ||||
393 | /*! \page aimInputsTetGen | |||
394 | * - <B>Surface_Mesh = NULL</B> <br> | |||
395 | * A Surface_Mesh link. | |||
396 | */ | |||
397 | } | |||
398 | ||||
399 | AIM_NOTNULL(*ainame, aimInfo, status){ if (*ainame == __null) { status = -307; aim_status(aimInfo, status, "tetgenAIM.cpp", 399, __func__, 1, "%s == NULL!", "*ainame" ); goto cleanup; } }; | |||
400 | ||||
401 | cleanup: | |||
402 | if (status != CAPS_SUCCESS0) AIM_FREE(*ainame){ EG_free(*ainame); *ainame = __null; }; | |||
403 | return status; | |||
404 | } | |||
405 | ||||
406 | ||||
407 | // ********************** AIM Function Break ***************************** | |||
408 | extern "C" int | |||
409 | aimUpdateState(void *instStore, void *aimInfo, capsValue *aimInputs) | |||
410 | { | |||
411 | int status; // Function return status | |||
412 | ||||
413 | char aimFile[PATH_MAX4096]; | |||
414 | char bodyNumberFile[128]; | |||
415 | ||||
416 | int MultiMesh, ibody; | |||
417 | aimMeshRef *surfaceMesh; | |||
418 | ||||
419 | // Incoming bodies | |||
420 | const char *intents; | |||
421 | ego *bodies = NULL__null; | |||
422 | int numBody = 0; | |||
423 | ||||
424 | aimStorage *tetgenInstance; | |||
425 | ||||
426 | tetgenInstance = (aimStorage *) instStore; | |||
427 | ||||
428 | // Cleanup previous aimStorage for the instance in case this is the second time through preAnalysis for the same instance | |||
429 | status = destroy_aimStorage(tetgenInstance); | |||
430 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 430, __func__, 0); goto cleanup; }; | |||
431 | ||||
432 | // Get AIM bodies | |||
433 | status = aim_getBodies(aimInfo, &intents, &numBody, &bodies); | |||
434 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 434, __func__, 0); goto cleanup; }; | |||
435 | ||||
436 | #ifdef DEBUG | |||
437 | printf(" tetgenAIM/aimPreAnalysis numBody = %d!\n", numBody); | |||
438 | #endif | |||
439 | ||||
440 | if (numBody <= 0 || bodies == NULL__null) { | |||
441 | AIM_ERROR(aimInfo, "No Bodies!"){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 441, __func__ , "No Bodies!"); }; | |||
442 | return CAPS_SOURCEERR-330; | |||
443 | } | |||
444 | ||||
445 | if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "SingleDomain") != 0 && | |||
446 | strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiFile") != 0 && | |||
447 | strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiDomain") != 0) { | |||
448 | AIM_ERROR(aimInfo, "Multiple_Mesh = '%s' must be 'SingleDomain', 'MultiFile', or 'MultiDomain'", aimInputs[Multiple_Mesh-1].vals.string){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 448, __func__ , "Multiple_Mesh = '%s' must be 'SingleDomain', 'MultiFile', or 'MultiDomain'" , aimInputs[Multiple_Mesh-1].vals.string); }; | |||
449 | status = CAPS_BADVALUE-311; | |||
450 | goto cleanup; | |||
451 | } | |||
452 | ||||
453 | // Get capsGroup name and index mapping | |||
454 | status = create_CAPSGroupAttrToIndexMap(numBody, | |||
455 | bodies, | |||
456 | -1, // Only search the face level of the EGADS body | |||
457 | &tetgenInstance->groupMap); | |||
458 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 458, __func__, 0); goto cleanup; }; | |||
459 | ||||
460 | ||||
461 | // Setup meshing input structure - mesher specific input gets set below before entering interface | |||
462 | tetgenInstance->meshInput.preserveSurfMesh = aimInputs[Preserve_Surf_Mesh-1].vals.integer; | |||
463 | tetgenInstance->meshInput.quiet = aimInputs[Mesh_Quiet_Flag-1].vals.integer; | |||
464 | ||||
465 | // Set tetgen specific mesh inputs | |||
466 | tetgenInstance->meshInput.tetgenInput.meshQuality_rad_edge = aimInputs[Quality_Rad_Edge-1].vals.real; | |||
467 | tetgenInstance->meshInput.tetgenInput.meshQuality_angle = aimInputs[Quality_Angle-1].vals.real; | |||
468 | tetgenInstance->meshInput.tetgenInput.verbose = aimInputs[Mesh_Verbose_Flag-1].vals.integer; | |||
469 | tetgenInstance->meshInput.tetgenInput.ignoreSurfaceExtract = aimInputs[Ignore_Surface_Mesh_Extraction-1].vals.integer; | |||
470 | tetgenInstance->meshInput.tetgenInput.meshTolerance = aimInputs[Mesh_Tolerance-1].vals.real; | |||
471 | ||||
472 | if (aimInputs[Regions-1].nullVal != IsNull) { | |||
473 | populate_regions(aimInfo, | |||
474 | &tetgenInstance->meshInput.tetgenInput.regions, | |||
475 | aimInputs[Regions-1].length, | |||
476 | aimInputs[Regions-1].vals.tuple); | |||
477 | } | |||
478 | if (aimInputs[Holes-1].nullVal != IsNull) { | |||
479 | populate_holes(&tetgenInstance->meshInput.tetgenInput.holes, | |||
480 | aimInputs[Holes-1].length, | |||
481 | aimInputs[Holes-1].vals.tuple); | |||
482 | } | |||
483 | ||||
484 | if (aimInputs[Mesh_Gen_Input_String-1].nullVal != IsNull) { | |||
485 | ||||
486 | AIM_STRDUP(tetgenInstance->meshInput.tetgenInput.meshInputString,{ if (tetgenInstance->meshInput.tetgenInput.meshInputString != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 487, __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" , 487, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshInput.tetgenInput.meshInputString" , aimInputs[Mesh_Gen_Input_String-1].vals.string); goto cleanup ; } } | |||
487 | aimInputs[Mesh_Gen_Input_String-1].vals.string, aimInfo, status){ if (tetgenInstance->meshInput.tetgenInput.meshInputString != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 487, __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" , 487, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshInput.tetgenInput.meshInputString" , aimInputs[Mesh_Gen_Input_String-1].vals.string); goto cleanup ; } }; | |||
488 | } | |||
489 | ||||
490 | status = populate_bndCondStruct_from_mapAttrToIndexStruct(&tetgenInstance->groupMap, | |||
491 | &tetgenInstance->meshInput.bndConds); | |||
492 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 492, __func__, 0); goto cleanup; }; | |||
493 | ||||
494 | ||||
495 | if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "SingleDomain") == 0) { | |||
496 | MultiMesh = 0; | |||
497 | } else if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiFile") == 0) { | |||
498 | MultiMesh = 1; | |||
499 | } else if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiDomain") == 0) { | |||
500 | MultiMesh = 2; | |||
501 | } else { | |||
502 | AIM_ERROR(aimInfo, "Developer error! Unknown Multiple_Mesh %s", aimInputs[Multiple_Mesh-1].vals.string){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 502, __func__ , "Developer error! Unknown Multiple_Mesh %s", aimInputs[Multiple_Mesh -1].vals.string); }; | |||
503 | status = CAPS_BADVALUE-311; | |||
504 | goto cleanup; | |||
505 | } | |||
506 | ||||
507 | // Get mesh | |||
508 | surfaceMesh = (aimMeshRef *)aimInputs[Surface_Mesh-1].vals.AIMptr; | |||
509 | ||||
510 | // Create/setup references | |||
511 | if (MultiMesh == 0 || MultiMesh == 2) { | |||
512 | ||||
513 | AIM_ALLOC(tetgenInstance->meshRef, 1, aimMeshRef, aimInfo, status){ if (tetgenInstance->meshRef != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 513, __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", 513, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef" , memorysize, "aimMeshRef"); goto cleanup; } }; | |||
514 | tetgenInstance->numMeshRef = 1; | |||
515 | ||||
516 | status = aim_initMeshRef(tetgenInstance->meshRef, aimVolumeMesh); | |||
517 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 517, __func__, 0); goto cleanup; }; | |||
518 | ||||
519 | // set the filename without extensions where the grid is written for solvers | |||
520 | ibody = 0; | |||
521 | if (aimInputs[Proj_Name-1].nullVal != IsNull) | |||
522 | snprintf(bodyNumberFile, 128, "%s_%d", aimInputs[Proj_Name-1].vals.string, ibody); | |||
523 | else | |||
524 | snprintf(bodyNumberFile, 128, TETGENFILE"tetgen_%d", ibody); | |||
525 | status = aim_file(aimInfo, bodyNumberFile, aimFile); | |||
526 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 526, __func__, 0); goto cleanup; }; | |||
527 | AIM_STRDUP(tetgenInstance->meshRef[0].fileName, aimFile, aimInfo, status){ if (tetgenInstance->meshRef[0].fileName != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 527, __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", 527, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshRef[0].fileName" , aimFile); goto cleanup; } }; | |||
528 | ||||
529 | } else if (MultiMesh == 1) { | |||
530 | ||||
531 | AIM_ALLOC(tetgenInstance->meshRef, surfaceMesh->nmap, aimMeshRef, aimInfo, status){ if (tetgenInstance->meshRef != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 531, __func__, 1, "AIM_ALLOC: %s != NULL" , "tetgenInstance->meshRef"); goto cleanup; } size_t memorysize = surfaceMesh->nmap; tetgenInstance->meshRef = (aimMeshRef *) EG_alloc(memorysize*sizeof(aimMeshRef)); if (tetgenInstance ->meshRef == __null) { status = -4; aim_status(aimInfo, status , "tetgenAIM.cpp", 531, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tetgenInstance->meshRef", memorysize, "aimMeshRef"); goto cleanup; } }; | |||
532 | tetgenInstance->numMeshRef = surfaceMesh->nmap; | |||
533 | ||||
534 | for (ibody = 0; ibody < surfaceMesh->nmap; ibody++) { | |||
535 | status = aim_initMeshRef(&tetgenInstance->meshRef[ibody], aimVolumeMesh); | |||
536 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 536, __func__, 0); goto cleanup; }; | |||
537 | } | |||
538 | ||||
539 | for (ibody = 0; ibody < surfaceMesh->nmap; ibody++) { | |||
540 | if (aimInputs[Proj_Name-1].nullVal != IsNull) | |||
541 | snprintf(bodyNumberFile, 128, "%s_%d", aimInputs[Proj_Name-1].vals.string, ibody); | |||
542 | else | |||
543 | snprintf(bodyNumberFile, 128, TETGENFILE"tetgen_%d", ibody); | |||
544 | ||||
545 | status = aim_file(aimInfo, bodyNumberFile, aimFile); | |||
546 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 546, __func__, 0); goto cleanup; }; | |||
547 | AIM_STRDUP(tetgenInstance->meshRef[ibody].fileName, aimFile, aimInfo, status){ if (tetgenInstance->meshRef[ibody].fileName != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 547 , __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", 547, __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshRef[ibody].fileName" , aimFile); goto cleanup; } }; | |||
548 | ||||
549 | AIM_ALLOC(tetgenInstance->meshRef[ibody].maps, 1, aimMeshTessMap, aimInfo, status){ if (tetgenInstance->meshRef[ibody].maps != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 549, __func__ , 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[ibody].maps" ); goto cleanup; } size_t memorysize = 1; tetgenInstance-> meshRef[ibody].maps = (aimMeshTessMap *) EG_alloc(memorysize* sizeof(aimMeshTessMap)); if (tetgenInstance->meshRef[ibody ].maps == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp" , 549, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef[ibody].maps" , memorysize, "aimMeshTessMap"); goto cleanup; } }; | |||
550 | tetgenInstance->meshRef[ibody].nmap = 1; | |||
551 | tetgenInstance->meshRef[ibody].maps[0].map = NULL__null; | |||
552 | tetgenInstance->meshRef[ibody].maps[0].tess = NULL__null; | |||
553 | } | |||
554 | ||||
555 | } | |||
556 | ||||
557 | ||||
558 | ||||
559 | status = CAPS_SUCCESS0; | |||
560 | cleanup: | |||
561 | return status; | |||
562 | } | |||
563 | ||||
564 | ||||
565 | // ********************** AIM Function Break ***************************** | |||
566 | extern "C" int | |||
567 | aimPreAnalysis(const void *instStore, void *aimInfo, capsValue *aimInputs) | |||
568 | { | |||
569 | int i, j, elem, ibody; // Indexing | |||
570 | ||||
571 | int status; // Return status | |||
572 | ||||
573 | const aimStorage *tetgenInstance; | |||
574 | ||||
575 | // Incoming bodies | |||
576 | const char *intents; | |||
577 | ego *bodies = NULL__null; | |||
578 | int numBody = 0; | |||
579 | ||||
580 | // Container for surface mesh | |||
581 | int numSurfaceMesh = 0; | |||
582 | meshStruct *surfaceMesh = NULL__null; | |||
583 | ||||
584 | aimMeshRef *meshRef = NULL__null; | |||
585 | ||||
586 | // Container for volume mesh | |||
587 | int numVolumeMesh = 0; | |||
588 | meshStruct *volumeMesh = NULL__null; | |||
589 | ||||
590 | // Attribute to index map | |||
591 | mapAttrToIndexStruct groupMap; | |||
592 | int lastAttr = 0; | |||
593 | ||||
594 | // Meshing related variables | |||
595 | meshElementStruct *element; | |||
596 | ||||
597 | double box[6], boxMax[6] = {0,0,0,0,0,0}; | |||
598 | int bodyBoundingBox = 0; | |||
599 | ||||
600 | int numElementCheck; | |||
601 | int MultiMesh = 0; | |||
602 | ||||
603 | // File ouput | |||
604 | char bodyNumberFile[42]; | |||
605 | //char filename[PATH_MAX]; | |||
606 | FILE *fp; | |||
| ||||
607 | ||||
608 | status = initiate_mapAttrToIndexStruct(&groupMap); | |||
609 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 609, __func__, 0); goto cleanup; }; | |||
610 | ||||
611 | // Get AIM bodies | |||
612 | status = aim_getBodies(aimInfo, &intents, &numBody, &bodies); | |||
613 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 613, __func__, 0); goto cleanup; }; | |||
614 | ||||
615 | #ifdef DEBUG | |||
616 | printf(" tetgenAIM/aimPreAnalysis numBody = %d!\n", numBody); | |||
617 | #endif | |||
618 | ||||
619 | if (numBody <= 0 || bodies == NULL__null) { | |||
620 | AIM_ERROR(aimInfo, "No Bodies!"){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 620, __func__ , "No Bodies!"); }; | |||
621 | return CAPS_SOURCEERR-330; | |||
622 | } | |||
623 | tetgenInstance = (const aimStorage *) instStore; | |||
624 | ||||
625 | // remove previous meshes | |||
626 | for (ibody = 0; ibody < tetgenInstance->numMeshRef; ibody++) { | |||
627 | status = aim_deleteMeshes(aimInfo, &tetgenInstance->meshRef[ibody]); | |||
628 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 628, __func__, 0); goto cleanup; }; | |||
629 | } | |||
630 | ||||
631 | // Get surface mesh | |||
632 | if (aimInputs[Surface_Mesh-1].nullVal == IsNull) { | |||
633 | 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", 633, __func__, "'Surface_Mesh' input must be linked to an output 'Surface_Mesh'" ); }; | |||
634 | status = CAPS_BADVALUE-311; | |||
635 | goto cleanup; | |||
636 | } | |||
637 | ||||
638 | // Get mesh | |||
639 | meshRef = (aimMeshRef *)aimInputs[Surface_Mesh-1].vals.AIMptr; | |||
640 | ||||
641 | if (meshRef->nmap != numBody) { | |||
642 | 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", 643, __func__, "Number of linked surface meshes (%d) does not match the number of bodies (%d)\n" , meshRef->nmap, numBody); } | |||
643 | meshRef->nmap, numBody){ aim_message(aimInfo, CERROR, Surface_Mesh, "tetgenAIM.cpp", 643, __func__, "Number of linked surface meshes (%d) does not match the number of bodies (%d)\n" , meshRef->nmap, numBody); }; | |||
644 | return CAPS_SOURCEERR-330; | |||
645 | } | |||
646 | ||||
647 | AIM_ALLOC(surfaceMesh, meshRef->nmap, meshStruct, aimInfo, status){ if (surfaceMesh != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 647, __func__, 1, "AIM_ALLOC: %s != NULL" , "surfaceMesh"); goto cleanup; } size_t memorysize = meshRef ->nmap; surfaceMesh = (meshStruct *) EG_alloc(memorysize*sizeof (meshStruct)); if (surfaceMesh == __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 647, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "surfaceMesh", memorysize, "meshStruct"); goto cleanup; } }; | |||
648 | numSurfaceMesh = meshRef->nmap; | |||
649 | ||||
650 | // Initiate surface meshes | |||
651 | for (i = 0; i < numBody; i++){ | |||
652 | status = initiate_meshStruct(&surfaceMesh[i]); | |||
653 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 653, __func__, 0); goto cleanup; }; | |||
654 | } | |||
655 | ||||
656 | for (i = 0; i < numBody; i++){ | |||
657 | status = copy_mapAttrToIndexStruct( &tetgenInstance->groupMap, | |||
658 | &surfaceMesh[i].groupMap ); | |||
659 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 659, __func__, 0); goto cleanup; }; | |||
660 | ||||
661 | surfaceMesh[i].egadsTess = meshRef->maps[i].tess; | |||
662 | status = mesh_surfaceMeshEGADSTess(aimInfo, &surfaceMesh[i], (int)false); | |||
663 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 663, __func__, 0); goto cleanup; }; | |||
664 | } | |||
665 | ||||
666 | if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "SingleDomain") == 0) { | |||
667 | MultiMesh = 0; | |||
668 | } else if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiFile") == 0) { | |||
669 | MultiMesh = 1; | |||
670 | } else if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiDomain") == 0) { | |||
671 | MultiMesh = 2; | |||
672 | } else { | |||
673 | AIM_ERROR(aimInfo, "Developer error! Unknown Multiple_Mesh %s", aimInputs[Multiple_Mesh-1].vals.string){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 673, __func__ , "Developer error! Unknown Multiple_Mesh %s", aimInputs[Multiple_Mesh -1].vals.string); }; | |||
674 | status = CAPS_BADVALUE-311; | |||
675 | goto cleanup; | |||
676 | } | |||
677 | ||||
678 | // Create/setup volume meshes | |||
679 | if (MultiMesh == 0) { | |||
680 | ||||
681 | // Determine which body is the bounding body based on size | |||
682 | bodyBoundingBox = 0; | |||
683 | if (numBody > 1) { | |||
684 | ||||
685 | for (ibody = 0; ibody < numBody; ibody++) { | |||
686 | ||||
687 | // Get bounding box for the body | |||
688 | status = EG_getBoundingBox(bodies[ibody], box); | |||
689 | if (status != EGADS_SUCCESS0) { | |||
690 | printf(" EG_getBoundingBox = %d\n\n", status); | |||
691 | return status; | |||
692 | } | |||
693 | ||||
694 | // Just copy the box coordinates on the first go around | |||
695 | if (ibody == 0) { | |||
696 | ||||
697 | memcpy(boxMax, box, sizeof(box)); | |||
698 | ||||
699 | // Set body as the bounding box (ie. farfield) | |||
700 | bodyBoundingBox = ibody; | |||
701 | ||||
702 | // Else compare with the "max" box size | |||
703 | } else if (boxMax[0] >= box[0] && | |||
704 | boxMax[1] >= box[1] && | |||
705 | boxMax[2] >= box[2] && | |||
706 | boxMax[3] <= box[3] && | |||
707 | boxMax[4] <= box[4] && | |||
708 | boxMax[5] <= box[5]) { | |||
709 | ||||
710 | // If bigger copy coordinates | |||
711 | memcpy(boxMax, box, sizeof(box)); | |||
712 | ||||
713 | // Set body as the bounding box (ie. farfield) | |||
714 | bodyBoundingBox = ibody; | |||
715 | } | |||
716 | } | |||
717 | } | |||
718 | ||||
719 | // Swap the surface element orientation so normals point out of the computational domain | |||
720 | for (ibody = 0; ibody < numBody; ibody++) { | |||
721 | if (ibody != bodyBoundingBox) { | |||
722 | // Swap two indices to reverse the normal vector of all elements on internal bodies | |||
723 | // so they point out of the domain | |||
724 | for (elem = 0; elem < surfaceMesh[ibody].numElement; elem++) { | |||
725 | ||||
726 | element = surfaceMesh[ibody].element + elem; | |||
727 | ||||
728 | // This should be valid for both Triangles and Quadrilaterals | |||
729 | i = element->connectivity[2]; | |||
730 | element->connectivity[2] = element->connectivity[0]; | |||
731 | element->connectivity[0] = i; | |||
732 | } | |||
733 | } | |||
734 | } | |||
735 | ||||
736 | numVolumeMesh = 1; | |||
737 | AIM_ALLOC(volumeMesh, numVolumeMesh, meshStruct, aimInfo, status){ if (volumeMesh != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 737, __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", 737, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh", memorysize, "meshStruct"); goto cleanup; } }; | |||
738 | ||||
739 | status = initiate_meshStruct(&volumeMesh[0]); | |||
740 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 740, __func__, 0); goto cleanup; }; | |||
741 | ||||
742 | // Combine mesh - temporary store the combined mesh in the volume mesh | |||
743 | status = mesh_combineMeshStruct(aimInfo, | |||
744 | numSurfaceMesh, | |||
745 | surfaceMesh, | |||
746 | &volumeMesh[0]); | |||
747 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 747, __func__, 0); goto cleanup; }; | |||
748 | ||||
749 | // Set reference meshes - All surfaces | |||
750 | volumeMesh[0].numReferenceMesh = numSurfaceMesh; | |||
751 | AIM_ALLOC(volumeMesh[0].referenceMesh, volumeMesh[0].numReferenceMesh, meshStruct, aimInfo, status){ if (volumeMesh[0].referenceMesh != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 751, __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", 751, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh[0].referenceMesh", memorysize, "meshStruct"); goto cleanup; } }; | |||
752 | ||||
753 | for (ibody = 0; ibody < numSurfaceMesh; ibody++) { | |||
754 | volumeMesh[0].referenceMesh[ibody] = surfaceMesh[ibody]; | |||
755 | } | |||
756 | ||||
757 | // Report surface mesh | |||
758 | printf("Number of surface: nodes - %d, elements - %d\n", | |||
759 | volumeMesh[0].numNode, volumeMesh[0].numElement); | |||
760 | ||||
761 | } else if (MultiMesh == 1) { | |||
762 | ||||
763 | AIM_ALLOC(volumeMesh, numBody, meshStruct, aimInfo, status){ if (volumeMesh != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 763, __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", 763, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh", memorysize, "meshStruct"); goto cleanup; } }; | |||
764 | numVolumeMesh = numBody; | |||
765 | ||||
766 | for (ibody = 0; ibody < numVolumeMesh; ibody++) { | |||
767 | status = initiate_meshStruct(&volumeMesh[ibody]); | |||
768 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 768, __func__, 0); goto cleanup; }; | |||
769 | ||||
770 | // Set reference mesh - One surface per body | |||
771 | volumeMesh[ibody].numReferenceMesh = 1; | |||
772 | AIM_ALLOC(volumeMesh[ibody].referenceMesh, volumeMesh[ibody].numReferenceMesh, meshStruct, aimInfo, status){ if (volumeMesh[ibody].referenceMesh != __null) { status = - 4; aim_status(aimInfo, status, "tetgenAIM.cpp", 772, __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", 772, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "volumeMesh[ibody].referenceMesh" , memorysize, "meshStruct"); goto cleanup; } }; | |||
773 | ||||
774 | volumeMesh[ibody].referenceMesh[0] = surfaceMesh[ibody]; | |||
775 | ||||
776 | // Report surface mesh | |||
777 | printf("Body %d number of surface: nodes - %d, elements - %d\n", | |||
778 | ibody+1, surfaceMesh[ibody].numNode, surfaceMesh[ibody].numElement); | |||
779 | } | |||
780 | ||||
781 | } else if (MultiMesh == 2) { | |||
782 | ||||
783 | numVolumeMesh = 1; | |||
784 | AIM_ALLOC(volumeMesh, numVolumeMesh, meshStruct, aimInfo, status){ if (volumeMesh != __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 784, __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", 784, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh", memorysize, "meshStruct"); goto cleanup; } }; | |||
785 | ||||
786 | status = initiate_meshStruct(&volumeMesh[0]); | |||
787 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 787, __func__, 0); goto cleanup; }; | |||
788 | ||||
789 | // Set reference meshes | |||
790 | volumeMesh[0].numReferenceMesh = numBody; | |||
791 | AIM_ALLOC(volumeMesh[0].referenceMesh, volumeMesh[0].numReferenceMesh, meshStruct, aimInfo, status){ if (volumeMesh[0].referenceMesh != __null) { status = -4; aim_status (aimInfo, status, "tetgenAIM.cpp", 791, __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", 791, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "volumeMesh[0].referenceMesh", memorysize, "meshStruct"); goto cleanup; } }; | |||
792 | ||||
793 | for (ibody = 0; ibody < numBody; ibody++) { | |||
794 | volumeMesh[0].referenceMesh[ibody] = surfaceMesh[ibody]; | |||
795 | ||||
796 | // Report surface mesh | |||
797 | printf("Body %d number of surface: nodes - %d, elements - %d\n", | |||
798 | ibody+1, surfaceMesh[ibody].numNode, surfaceMesh[ibody].numElement); | |||
799 | } | |||
800 | ||||
801 | } | |||
802 | ||||
803 | // Call tetgen volume mesh interface | |||
804 | if (MultiMesh == 0) { | |||
805 | printf("Getting volume mesh\n"); | |||
806 | ||||
807 | status = tetgen_VolumeMesh(aimInfo, | |||
808 | tetgenInstance->meshInput, | |||
809 | &tetgenInstance->groupMap, | |||
810 | tetgenInstance->meshRef[0].fileName, | |||
811 | 1, | |||
812 | &volumeMesh[0], | |||
813 | &volumeMesh[0]); | |||
814 | ||||
815 | if (status != CAPS_SUCCESS0) { | |||
816 | AIM_ERROR(aimInfo, "TetGen volume mesh failed!!!!"){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 816, __func__ , "TetGen volume mesh failed!!!!"); }; | |||
817 | goto cleanup; | |||
818 | } | |||
819 | ||||
820 | } else if (MultiMesh == 1) { | |||
821 | ||||
822 | for (ibody = 0; ibody < numVolumeMesh; ibody++) { | |||
823 | ||||
824 | // Call tetgen volume mesh interface for each body | |||
825 | printf("Getting volume mesh for body %d (of %d)\n", ibody+1, numBody); | |||
826 | ||||
827 | // Get capsGroup name and index mapping | |||
828 | status = create_CAPSGroupAttrToIndexMap(1, | |||
829 | &bodies[ibody], | |||
830 | -1, // Only search the face level of the EGADS body | |||
831 | &groupMap); | |||
832 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 832, __func__, 0); goto cleanup; }; | |||
833 | ||||
834 | for (i = 0; i < groupMap.numAttribute; i++) { | |||
835 | groupMap.attributeIndex[i] += lastAttr; | |||
836 | } | |||
837 | ||||
838 | status = tetgen_VolumeMesh(aimInfo, | |||
839 | tetgenInstance->meshInput, | |||
840 | &groupMap, | |||
841 | tetgenInstance->meshRef[ibody].fileName, | |||
842 | 1, | |||
843 | &volumeMesh[ibody].referenceMesh[0], | |||
844 | &volumeMesh[ibody]); | |||
845 | ||||
846 | if (status != CAPS_SUCCESS0) { | |||
847 | AIM_ERROR(aimInfo, "TetGen volume mesh failed on body - %d!!!!", ibody+1){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 847, __func__ , "TetGen volume mesh failed on body - %d!!!!", ibody+1); }; | |||
848 | goto cleanup; | |||
849 | } | |||
850 | ||||
851 | lastAttr = groupMap.attributeIndex[groupMap.numAttribute-1]; | |||
852 | ||||
853 | status = destroy_mapAttrToIndexStruct(&groupMap); | |||
854 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 854, __func__, 0); goto cleanup; }; | |||
855 | } | |||
856 | ||||
857 | } else if (MultiMesh == 2) { | |||
858 | ||||
859 | printf("Getting volume mesh\n"); | |||
860 | ||||
861 | status = tetgen_VolumeMesh(aimInfo, | |||
862 | tetgenInstance->meshInput, | |||
863 | &tetgenInstance->groupMap, | |||
864 | tetgenInstance->meshRef[0].fileName, | |||
865 | volumeMesh[0].numReferenceMesh, | |||
866 | volumeMesh[0].referenceMesh, | |||
867 | &volumeMesh[0]); | |||
868 | ||||
869 | if (status != CAPS_SUCCESS0) { | |||
870 | AIM_ERROR(aimInfo, "TetGen volume mesh failed!!!!"){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 870, __func__ , "TetGen volume mesh failed!!!!"); }; | |||
871 | goto cleanup; | |||
872 | } | |||
873 | } | |||
874 | ||||
875 | for (i = 0; i < numVolumeMesh; i++) { | |||
876 | ||||
877 | // Check to make sure the volume mesher didn't add any unaccounted for points/faces | |||
878 | numElementCheck = 0; | |||
879 | for (j = 0; j < volumeMesh[i].numReferenceMesh; j++) { | |||
880 | numElementCheck += volumeMesh[i].referenceMesh[j].numElement; | |||
881 | } | |||
882 | ||||
883 | if (volumeMesh[i].meshQuickRef.useStartIndex == (int) false && | |||
884 | volumeMesh[i].meshQuickRef.useListIndex == (int) false) { | |||
885 | ||||
886 | status = mesh_retrieveNumMeshElements(volumeMesh[i].numElement, | |||
887 | volumeMesh[i].element, | |||
888 | Triangle, | |||
889 | &volumeMesh[i].meshQuickRef.numTriangle); | |||
890 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 890, __func__, 0); goto cleanup; }; | |||
891 | ||||
892 | status = mesh_retrieveNumMeshElements(volumeMesh[i].numElement, | |||
893 | volumeMesh[i].element, | |||
894 | Quadrilateral, | |||
895 | &volumeMesh[i].meshQuickRef.numQuadrilateral); | |||
896 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 896, __func__, 0); goto cleanup; }; | |||
897 | ||||
898 | } | |||
899 | ||||
900 | snprintf(bodyNumberFile, 42, NODATATRANSFER"noDataTransfer.%d", i); | |||
901 | status = aim_rmFile(aimInfo, bodyNumberFile); | |||
902 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 902, __func__, 0); goto cleanup; }; | |||
903 | ||||
904 | if (numElementCheck != volumeMesh[i].meshQuickRef.numTriangle + | |||
905 | volumeMesh[i].meshQuickRef.numQuadrilateral) { | |||
906 | ||||
907 | fp = aim_fopen(aimInfo, bodyNumberFile,"w"); | |||
908 | if (fp == NULL__null) { | |||
909 | AIM_ERROR(aimInfo, "Failed to open '%s'", bodyNumberFile){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 909, __func__ , "Failed to open '%s'", bodyNumberFile); }; | |||
910 | status = CAPS_IOERR-332; | |||
911 | goto cleanup; | |||
912 | } | |||
913 | fprintf(fp, "shucks..."); | |||
914 | fclose(fp); fp = NULL__null; | |||
915 | ||||
916 | printf("Volume mesher did not preserve surface elements - data transfer will NOT be possible.\n"); | |||
917 | } | |||
918 | } | |||
919 | ||||
920 | status = CAPS_SUCCESS0; | |||
921 | ||||
922 | cleanup: | |||
923 | ||||
924 | // Destroy volumeMesh allocated arrays | |||
925 | if (volumeMesh
| |||
926 | for (i = 0; i < numVolumeMesh; i++) { | |||
927 | (void) destroy_meshStruct(&volumeMesh[i]); | |||
928 | } | |||
929 | AIM_FREE(volumeMesh){ EG_free(volumeMesh); volumeMesh = __null; }; | |||
930 | } | |||
931 | ||||
932 | for (i = 0; i < numSurfaceMesh; i++){ | |||
933 | destroy_meshStruct(&surfaceMesh[i]); | |||
934 | } | |||
935 | AIM_FREE(surfaceMesh){ EG_free(surfaceMesh); surfaceMesh = __null; }; | |||
936 | ||||
937 | destroy_mapAttrToIndexStruct(&groupMap); | |||
938 | ||||
939 | if (fp != NULL__null) fclose(fp); | |||
| ||||
940 | ||||
941 | ||||
942 | return status; | |||
943 | } | |||
944 | ||||
945 | ||||
946 | /* the execution code from above should be moved here */ | |||
947 | extern "C" int | |||
948 | aimExecute(/*@unused@*/ const void *instStore, /*@unused@*/ void *aimStruc, int *state) | |||
949 | { | |||
950 | *state = 0; | |||
951 | return CAPS_SUCCESS0; | |||
952 | } | |||
953 | ||||
954 | ||||
955 | /* no longer optional and needed for restart */ | |||
956 | extern "C" int | |||
957 | aimPostAnalysis(void *instStore, void *aimInfo, | |||
958 | int restart, capsValue *aimInputs) | |||
959 | { | |||
960 | int status = CAPS_SUCCESS0; | |||
961 | ||||
962 | // Incoming bodies | |||
963 | const char *intents; | |||
964 | ego *bodies = NULL__null; | |||
965 | int numBody = 0; | |||
966 | ||||
967 | // Container for volume mesh | |||
968 | int numSurfaceMesh = 0; | |||
969 | aimMeshRef *surfaceMesh=NULL__null; | |||
970 | ||||
971 | int i, j, ibody, nodeOffset; | |||
972 | int MultiMesh, numVolNode; | |||
973 | ||||
974 | char volFile[PATH_MAX4096]; | |||
975 | char bodyNumberFile[42]; | |||
976 | FILE *fp = NULL__null; | |||
977 | ||||
978 | int state, numSurfNode; | |||
979 | ego body; | |||
980 | ||||
981 | aimStorage *tetgenInstance; | |||
982 | aimMesh mesh; | |||
983 | ||||
984 | tetgenInstance = (aimStorage *) instStore; | |||
985 | ||||
986 | // Get AIM bodies | |||
987 | status = aim_getBodies(aimInfo, &intents, &numBody, &bodies); | |||
988 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 988, __func__, 0); goto cleanup; }; | |||
989 | ||||
990 | // Get mesh | |||
991 | surfaceMesh = (aimMeshRef *)aimInputs[Surface_Mesh-1].vals.AIMptr; | |||
992 | AIM_NOTNULL(surfaceMesh, aimInfo, status){ if (surfaceMesh == __null) { status = -307; aim_status(aimInfo , status, "tetgenAIM.cpp", 992, __func__, 1, "%s == NULL!", "surfaceMesh" ); goto cleanup; } }; | |||
993 | numSurfaceMesh = surfaceMesh->nmap; | |||
994 | ||||
995 | if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "SingleDomain") == 0) { | |||
996 | MultiMesh = 0; | |||
997 | } else if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiFile") == 0) { | |||
998 | MultiMesh = 1; | |||
999 | } else if (strcasecmp(aimInputs[Multiple_Mesh-1].vals.string, "MultiDomain") == 0) { | |||
1000 | MultiMesh = 2; | |||
1001 | } else { | |||
1002 | AIM_ERROR(aimInfo, "Developer error! Unknown Multiple_Mesh %s", aimInputs[Multiple_Mesh-1].vals.string){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 1002, __func__ , "Developer error! Unknown Multiple_Mesh %s", aimInputs[Multiple_Mesh -1].vals.string); }; | |||
1003 | status = CAPS_BADVALUE-311; | |||
1004 | goto cleanup; | |||
1005 | } | |||
1006 | ||||
1007 | // Create/setup mesh maps | |||
1008 | if (MultiMesh == 0 || MultiMesh == 2) { | |||
1009 | ||||
1010 | ibody = 0; | |||
1011 | ||||
1012 | if (MultiMesh == 2) { | |||
1013 | snprintf(volFile, PATH_MAX4096, "%s.txt", tetgenInstance->meshRef[0].fileName); | |||
1014 | fp = fopen(volFile, "r"); | |||
1015 | if (fp == NULL__null) { | |||
1016 | AIM_ERROR(aimInfo, "Failed to open '%s'!", volFile){ aim_message(aimInfo, CERROR, 0 , "tetgenAIM.cpp", 1016, __func__ , "Failed to open '%s'!", volFile); }; | |||
1017 | status = CAPS_IOERR-332; | |||
1018 | goto cleanup; | |||
1019 | } | |||
1020 | } | |||
1021 | ||||
1022 | snprintf(bodyNumberFile, 42, NODATATRANSFER"noDataTransfer.%d", ibody); | |||
1023 | if (aim_isFile(aimInfo, bodyNumberFile) == CAPS_SUCCESS0) { | |||
1024 | // data transfer and sensitvities are not available | |||
1025 | tetgenInstance->meshRef[0].nmap = 0; | |||
1026 | tetgenInstance->meshRef[0].maps = NULL__null; | |||
1027 | ||||
1028 | } else { | |||
1029 | ||||
1030 | AIM_ALLOC(tetgenInstance->meshRef[0].maps, numSurfaceMesh, aimMeshTessMap, aimInfo, status){ if (tetgenInstance->meshRef[0].maps != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 1030, __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" , 1030, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef[0].maps" , memorysize, "aimMeshTessMap"); goto cleanup; } }; | |||
1031 | tetgenInstance->meshRef[0].nmap = numSurfaceMesh; | |||
1032 | ||||
1033 | nodeOffset = 0; | |||
1034 | for (ibody = 0; ibody < numSurfaceMesh; ibody++) { | |||
1035 | tetgenInstance->meshRef[0].maps[ibody].tess = NULL__null; | |||
1036 | tetgenInstance->meshRef[0].maps[ibody].map = NULL__null; | |||
1037 | ||||
1038 | tetgenInstance->meshRef[0].maps[ibody].tess = surfaceMesh->maps[ibody].tess; | |||
1039 | ||||
1040 | status = EG_statusTessBody(surfaceMesh->maps[ibody].tess, &body, &state, &numSurfNode); | |||
1041 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1041, __func__, 0); goto cleanup; }; | |||
1042 | ||||
1043 | AIM_ALLOC(tetgenInstance->meshRef[0].maps[ibody].map, numSurfNode, int, aimInfo, status){ if (tetgenInstance->meshRef[0].maps[ibody].map != __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 1043, __func__, 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[0].maps[ibody].map" ); goto cleanup; } size_t memorysize = numSurfNode; 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" , 1043, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef[0].maps[ibody].map" , memorysize, "int"); goto cleanup; } }; | |||
1044 | for (i = 0; i < numSurfNode; i++) | |||
1045 | tetgenInstance->meshRef[0].maps[ibody].map[i] = nodeOffset + i+1; | |||
1046 | ||||
1047 | if (MultiMesh == 0) { | |||
1048 | nodeOffset += numSurfNode; | |||
1049 | } else { | |||
1050 | fscanf(fp, "%d", &numVolNode); | |||
1051 | nodeOffset += numVolNode; | |||
1052 | } | |||
1053 | } | |||
1054 | } | |||
1055 | ||||
1056 | } else if (MultiMesh == 1) { | |||
1057 | ||||
1058 | for (ibody = 0; ibody < numBody; ibody++) { | |||
1059 | snprintf(bodyNumberFile, 42, NODATATRANSFER"noDataTransfer.%d", ibody); | |||
1060 | if (aim_isFile(aimInfo, bodyNumberFile) == CAPS_SUCCESS0) continue; | |||
1061 | ||||
1062 | tetgenInstance->meshRef[ibody].maps[0].tess = surfaceMesh->maps[ibody].tess; | |||
1063 | ||||
1064 | status = EG_statusTessBody(surfaceMesh->maps[ibody].tess, &body, &state, &numSurfNode); | |||
1065 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1065, __func__, 0); goto cleanup; }; | |||
1066 | ||||
1067 | AIM_ALLOC(tetgenInstance->meshRef[ibody].maps[0].map, numSurfNode, int, aimInfo, status){ if (tetgenInstance->meshRef[ibody].maps[0].map != __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 1067, __func__, 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[ibody].maps[0].map" ); goto cleanup; } size_t memorysize = numSurfNode; 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" , 1067, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tetgenInstance->meshRef[ibody].maps[0].map" , memorysize, "int"); goto cleanup; } }; | |||
1068 | for (i = 0; i < numSurfNode; i++) | |||
1069 | tetgenInstance->meshRef[ibody].maps[0].map[i] = i+1; | |||
1070 | } | |||
1071 | } | |||
1072 | ||||
1073 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { | |||
1074 | ||||
1075 | AIM_ALLOC(tetgenInstance->meshRef[i].bnds, tetgenInstance->groupMap.numAttribute, aimMeshBnd, aimInfo, status){ if (tetgenInstance->meshRef[i].bnds != __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 1075, __func__ , 1, "AIM_ALLOC: %s != NULL", "tetgenInstance->meshRef[i].bnds" ); goto cleanup; } size_t memorysize = tetgenInstance->groupMap .numAttribute; tetgenInstance->meshRef[i].bnds = (aimMeshBnd *) EG_alloc(memorysize*sizeof(aimMeshBnd)); if (tetgenInstance ->meshRef[i].bnds == __null) { status = -4; aim_status(aimInfo , status, "tetgenAIM.cpp", 1075, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tetgenInstance->meshRef[i].bnds", memorysize, "aimMeshBnd" ); goto cleanup; } }; | |||
1076 | tetgenInstance->meshRef[i].nbnd = tetgenInstance->groupMap.numAttribute; | |||
1077 | for (j = 0; j < tetgenInstance->meshRef[i].nbnd; j++) { | |||
1078 | status = aim_initMeshBnd(tetgenInstance->meshRef[i].bnds + j); | |||
1079 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1079, __func__, 0); goto cleanup; }; | |||
1080 | } | |||
1081 | ||||
1082 | for (j = 0; j < tetgenInstance->meshRef[i].nbnd; j++) { | |||
1083 | AIM_STRDUP(tetgenInstance->meshRef[i].bnds[j].groupName, tetgenInstance->groupMap.attributeName[j], aimInfo, status){ if (tetgenInstance->meshRef[i].bnds[j].groupName != __null ) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 1083, __func__, 1, "AIM_STRDUP: %s != NULL!", "tetgenInstance->meshRef[i].bnds[j].groupName" ); goto cleanup; } tetgenInstance->meshRef[i].bnds[j].groupName = EG_strdup(tetgenInstance->groupMap.attributeName[j]); if (tetgenInstance->meshRef[i].bnds[j].groupName == __null) { status = -4; aim_status(aimInfo, status, "tetgenAIM.cpp", 1083 , __func__, 2, "AIM_STRDUP: %s %s", "tetgenInstance->meshRef[i].bnds[j].groupName" , tetgenInstance->groupMap.attributeName[j]); goto cleanup ; } }; | |||
1084 | tetgenInstance->meshRef[i].bnds[j].ID = tetgenInstance->groupMap.attributeIndex[j]; | |||
1085 | } | |||
1086 | } | |||
1087 | ||||
1088 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { | |||
1089 | status = aim_queryMeshes( aimInfo, Mesh_Format, ANALYSISIN, &tetgenInstance->meshRef[i] ); | |||
1090 | if (status > 0) { | |||
1091 | mesh.meshData = NULL__null; | |||
1092 | mesh.meshRef = &tetgenInstance->meshRef[i]; | |||
1093 | ||||
1094 | status = aim_readBinaryUgrid(aimInfo, &mesh); | |||
1095 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1095, __func__, 0); goto cleanup; }; | |||
1096 | ||||
1097 | status = aim_writeMeshes(aimInfo, Mesh_Format, ANALYSISIN, &mesh); | |||
1098 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1098, __func__, 0); goto cleanup; }; | |||
1099 | ||||
1100 | status = aim_freeMeshData(mesh.meshData); | |||
1101 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1101, __func__, 0); goto cleanup; }; | |||
1102 | AIM_FREE(mesh.meshData){ EG_free(mesh.meshData); mesh.meshData = __null; }; | |||
1103 | } | |||
1104 | else | |||
1105 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1105, __func__, 0); goto cleanup; }; | |||
1106 | } | |||
1107 | ||||
1108 | cleanup: | |||
1109 | if (fp != NULL__null) fclose(fp); | |||
1110 | return status; | |||
1111 | } | |||
1112 | ||||
1113 | ||||
1114 | extern "C" int | |||
1115 | aimOutputs(/*@unused@*/ void *instStore, /*@unused@*/ void *aimInfo, int index, | |||
1116 | char **aoname, capsValue *form) | |||
1117 | { | |||
1118 | /*! \page aimOutputsTetGen AIM Outputs | |||
1119 | * The following list outlines the TetGen AIM outputs available through the AIM interface. | |||
1120 | */ | |||
1121 | ||||
1122 | int status = CAPS_SUCCESS0; | |||
1123 | ||||
1124 | #ifdef DEBUG | |||
1125 | printf(" tetgenAIM/aimOutputs index = %d!\n", index); | |||
1126 | #endif | |||
1127 | if (index == NumberOfElement) { | |||
1128 | *aoname = EG_strdup("NumberOfElement"); | |||
1129 | form->type = Integer; | |||
1130 | form->vals.integer = 0; | |||
1131 | ||||
1132 | /*! \page aimOutputsTetGen | |||
1133 | * - <B> NumberOfElement </B> <br> | |||
1134 | * Number of elements in the surface mesh | |||
1135 | */ | |||
1136 | ||||
1137 | } else if (index == NumberOfNode) { | |||
1138 | *aoname = EG_strdup("NumberOfNode"); | |||
1139 | form->type = Integer; | |||
1140 | form->vals.integer = 0; | |||
1141 | ||||
1142 | /*! \page aimOutputsTetGen | |||
1143 | * - <B> NumberOfNode </B> <br> | |||
1144 | * Number of vertices in the surface mesh | |||
1145 | */ | |||
1146 | ||||
1147 | } else if (index == Volume_Mesh) { | |||
1148 | *aoname = AIM_NAME(Volume_Mesh)EG_strdup("Volume_Mesh"); | |||
1149 | form->type = PointerMesh; | |||
1150 | form->dim = Vector; | |||
1151 | form->lfixed = Change; | |||
1152 | form->sfixed = Fixed; | |||
1153 | form->vals.AIMptr = NULL__null; | |||
1154 | form->nullVal = IsNull; | |||
1155 | ||||
1156 | /*! \page aimOutputsTetGen | |||
1157 | * - <B> Volume_Mesh </B> <br> | |||
1158 | * The volume mesh for a link | |||
1159 | */ | |||
1160 | ||||
1161 | } else { | |||
1162 | status = CAPS_BADINDEX-304; | |||
1163 | AIM_STATUS(aimInfo, status, "Unknown output index %d!", index)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1163, __func__, 2, "Unknown output index %d!", index); goto cleanup; }; | |||
1164 | } | |||
1165 | ||||
1166 | AIM_NOTNULL(*aoname, aimInfo, status){ if (*aoname == __null) { status = -307; aim_status(aimInfo, status, "tetgenAIM.cpp", 1166, __func__, 1, "%s == NULL!", "*aoname" ); goto cleanup; } }; | |||
1167 | ||||
1168 | cleanup: | |||
1169 | if (status != CAPS_SUCCESS0) AIM_FREE(*aoname){ EG_free(*aoname); *aoname = __null; }; | |||
1170 | return status; | |||
1171 | } | |||
1172 | ||||
1173 | ||||
1174 | extern "C" int | |||
1175 | aimCalcOutput(void *instStore, void *aimInfo, int index, capsValue *val) | |||
1176 | { | |||
1177 | int i, status = CAPS_SUCCESS0; | |||
1178 | int numElement, numNodes; | |||
1179 | int nVertex, nTri, nQuad, nTet, nPyramid, nPrism, nHex; | |||
1180 | aimStorage *tetgenInstance; | |||
1181 | aimMesh mesh; | |||
1182 | ||||
1183 | #ifdef DEBUG | |||
1184 | printf(" tetgenAIM/aimCalcOutput index = %d!\n", index); | |||
1185 | #endif | |||
1186 | tetgenInstance = (aimStorage *) instStore; | |||
1187 | ||||
1188 | if (NumberOfElement == index) { | |||
1189 | ||||
1190 | // Count the total number of surface elements | |||
1191 | numElement = 0; | |||
1192 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { | |||
1193 | status = aim_readBinaryUgridHeader(aimInfo, &tetgenInstance->meshRef[i], | |||
1194 | &nVertex, &nTri, &nQuad, | |||
1195 | &nTet, &nPyramid, &nPrism, &nHex); | |||
1196 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1196, __func__, 0); goto cleanup; }; | |||
1197 | ||||
1198 | numElement += nTri + nQuad + nTet + nPyramid + nPrism + nHex; | |||
1199 | } | |||
1200 | ||||
1201 | val->vals.integer = numElement; | |||
1202 | ||||
1203 | } else if (NumberOfNode == index) { | |||
1204 | ||||
1205 | // Count the total number of surface vertices | |||
1206 | numNodes = 0; | |||
1207 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { | |||
1208 | status = aim_readBinaryUgridHeader(aimInfo, &tetgenInstance->meshRef[i], | |||
1209 | &nVertex, &nTri, &nQuad, | |||
1210 | &nTet, &nPyramid, &nPrism, &nHex); | |||
1211 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1211, __func__, 0); goto cleanup; }; | |||
1212 | ||||
1213 | numNodes += nVertex; | |||
1214 | } | |||
1215 | ||||
1216 | val->vals.integer = numNodes; | |||
1217 | ||||
1218 | } else if (Volume_Mesh == index) { | |||
1219 | ||||
1220 | for (i = 0; i < tetgenInstance->numMeshRef; i++) { | |||
1221 | status = aim_queryMeshes( aimInfo, Volume_Mesh, ANALYSISOUT, &tetgenInstance->meshRef[i] ); | |||
1222 | if (status > 0) { | |||
1223 | mesh.meshData = NULL__null; | |||
1224 | mesh.meshRef = &tetgenInstance->meshRef[i]; | |||
1225 | ||||
1226 | status = aim_readBinaryUgrid(aimInfo, &mesh); | |||
1227 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1227, __func__, 0); goto cleanup; }; | |||
1228 | ||||
1229 | status = aim_writeMeshes(aimInfo, Volume_Mesh, ANALYSISOUT, &mesh); | |||
1230 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1230, __func__, 0); goto cleanup; }; | |||
1231 | ||||
1232 | status = aim_freeMeshData(mesh.meshData); | |||
1233 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1233, __func__, 0); goto cleanup; }; | |||
1234 | AIM_FREE(mesh.meshData){ EG_free(mesh.meshData); mesh.meshData = __null; }; | |||
1235 | } | |||
1236 | else | |||
1237 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1237, __func__, 0); goto cleanup; }; | |||
1238 | } | |||
1239 | ||||
1240 | // Return the volume mesh references | |||
1241 | val->nrow = tetgenInstance->numMeshRef; | |||
1242 | val->vals.AIMptr = tetgenInstance->meshRef; | |||
1243 | ||||
1244 | } else { | |||
1245 | ||||
1246 | status = CAPS_BADINDEX-304; | |||
1247 | AIM_STATUS(aimInfo, status, "Unknown output index %d!", index)if (status != 0) { aim_status(aimInfo, status, "tetgenAIM.cpp" , 1247, __func__, 2, "Unknown output index %d!", index); goto cleanup; }; | |||
1248 | ||||
1249 | } | |||
1250 | ||||
1251 | cleanup: | |||
1252 | ||||
1253 | return status; | |||
1254 | } | |||
1255 | ||||
1256 | extern "C" void | |||
1257 | aimCleanup(void *instStore) | |||
1258 | { | |||
1259 | int status; // Function return status | |||
1260 | aimStorage *tetgenInstance; | |||
1261 | ||||
1262 | #ifdef DEBUG | |||
1263 | printf(" tetgenAIM/aimCleanup!\n"); | |||
1264 | #endif | |||
1265 | tetgenInstance = (aimStorage *) instStore; | |||
1266 | ||||
1267 | status = destroy_aimStorage(tetgenInstance); | |||
1268 | if (status != CAPS_SUCCESS0) | |||
1269 | printf("Status = %d, tetgenAIM aimStorage cleanup!!!\n", status); | |||
1270 | ||||
1271 | EG_free(tetgenInstance); | |||
1272 | } |