Bug Summary

File:aim/tetgen/tetgenAIM.cpp
Warning:line 640, column 9
Value stored to 'status' is never read

Annotated Source Code

Press '?' to see keyboard shortcuts

clang -cc1 -triple x86_64-pc-linux-gnu -analyze -disable-free -disable-llvm-verifier -discard-value-names -main-file-name tetgenAIM.cpp -analyzer-store=region -analyzer-opt-analyze-nested-blocks -analyzer-checker=core -analyzer-checker=apiModeling -analyzer-checker=unix -analyzer-checker=deadcode -analyzer-checker=cplusplus -analyzer-checker=security.insecureAPI.UncheckedReturn -analyzer-checker=security.insecureAPI.getpw -analyzer-checker=security.insecureAPI.gets -analyzer-checker=security.insecureAPI.mktemp -analyzer-checker=security.insecureAPI.mkstemp -analyzer-checker=security.insecureAPI.vfork -analyzer-checker=nullability.NullPassedToNonnull -analyzer-checker=nullability.NullReturnedFromNonnull -analyzer-output plist -w -setup-static-analyzer -mrelocation-model pic -pic-level 2 -mthread-model posix -mframe-pointer=none -fmath-errno -fno-rounding-math -masm-verbose -mconstructor-aliases -munwind-tables -target-cpu x86-64 -dwarf-column-info -fno-split-dwarf-inlining -debugger-tuning=gdb -resource-dir /usr/lib/llvm-10/lib/clang/10.0.0 -D REVISION=7.6 -I /home/jenkins/workspace/ESP_Stanalizer/LINUX64/CAPS/scan-build/ESP/LINUX64/include -I ../utils -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/x86_64-linux-gnu/c++/7.5.0 -internal-isystem /usr/lib/gcc/x86_64-linux-gnu/7.5.0/../../../../include/c++/7.5.0/backward -internal-isystem /usr/local/include -internal-isystem /usr/lib/llvm-10/lib/clang/10.0.0/include -internal-externc-isystem /usr/include/x86_64-linux-gnu -internal-externc-isystem /include -internal-externc-isystem /usr/include -O2 -Wno-dangling-else -Wno-parentheses -Wno-unused-result -Wno-format-truncation -fdeprecated-macro -fdebug-compilation-dir /home/jenkins/workspace/ESP_Stanalizer/LINUX64/CAPS/scan-build/CAPS/aim/tetgen -ferror-limit 19 -fmessage-length 0 -fgnuc-version=4.2.1 -fobjc-runtime=gcc -fcxx-exceptions -fexceptions -fdiagnostics-show-option -vectorize-loops -vectorize-slp -analyzer-output=html -faddrsig -o /home/jenkins/workspace/ESP_Stanalizer/LINUX64/CAPS/scan-build/scanCAPS/2022-02-21-093618-41363-1 -x c++ tetgenAIM.cpp
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
59enum 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
79enum 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
90typedef 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
106static 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
135extern "C" int
136aimInitialize(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
179cleanup:
180 if (status != CAPS_SUCCESS0) AIM_FREE(*instStore){ EG_free(*instStore); *instStore = __null; };
181 return CAPS_SUCCESS0;
182}
183
184
185extern "C" int
186aimInputs(/*@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
402cleanup:
403 if (status != CAPS_SUCCESS0) AIM_FREE(*ainame){ EG_free(*ainame); *ainame = __null; };
404 return status;
405}
406
407
408extern "C" int
409aimPreAnalysis(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
798cleanup:
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 */
814extern "C" int
815aimExecute(/*@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 */
823extern "C" int
824aimPostAnalysis(/*@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
924cleanup:
925 return status;
926}
927
928
929extern "C" int
930aimOutputs(/*@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
983cleanup:
984 if (status != CAPS_SUCCESS0) AIM_FREE(*aoname){ EG_free(*aoname); *aoname = __null; };
985 return status;
986}
987
988
989extern "C" int
990aimCalcOutput(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
1066cleanup:
1067
1068 return status;
1069}
1070
1071extern "C" void
1072aimCleanup(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}