File: | mystranAIM.c |
Warning: | line 821, column 13 Dereference of null pointer |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* | |||
2 | * CAPS: Computational Aircraft Prototype Syntheses | |||
3 | * | |||
4 | * mystran 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 | * \tableofcontents | |||
14 | * \section overviewMYSTRAN MYSTRAN AIM Overview | |||
15 | * A module in the Computational Aircraft Prototype Syntheses (CAPS) has been developed to interact (primarily | |||
16 | * through input files) with the finite element structural solver MYSTRAN \cite MYSTRAN. MYSTRAN is an open source, | |||
17 | * general purpose, linear finite element analysis computer program written by Dr. Bill Case. Available at, | |||
18 | * http://www.mystran.com/, MYSTRAN currently supports Linux and Windows operating systems. | |||
19 | * | |||
20 | * | |||
21 | * An outline of the AIM's inputs, outputs and attributes are provided in \ref aimInputsMYSTRAN and | |||
22 | * \ref aimOutputsMYSTRAN and \ref attributeMYSTRAN, respectively. | |||
23 | * | |||
24 | * The MYSTRAN AIM can automatically execute MYSTRAN, with details provided in \ref aimExecuteMYSTRAN. | |||
25 | * | |||
26 | * Details of the AIM's automated data transfer capabilities are outlined in \ref dataTransferMYSTRAN | |||
27 | * | |||
28 | *\section mystranExamples Examples | |||
29 | * An example problem using the MYSTRAN AIM may be found at \ref mystranExample. | |||
30 | * | |||
31 | * \section clearanceMYSTRAN Clearance Statement | |||
32 | * This software has been cleared for public release on 05 Nov 2020, case number 88ABW-2020-3462. | |||
33 | */ | |||
34 | ||||
35 | ||||
36 | /*! \page attributeMYSTRAN MYSTRAN AIM attributes | |||
37 | * The following list of attributes are required for the MYSTRAN AIM inside the geometry input. | |||
38 | * | |||
39 | * - <b> capsAIM</b> This attribute is a CAPS requirement to indicate the analysis the geometry | |||
40 | * representation supports. | |||
41 | * | |||
42 | * - <b> capsGroup</b> This is a name assigned to any geometric body. This body could be a solid, surface, face, wire, edge or node. | |||
43 | * Recall that a string in ESP starts with a $. For example, attribute <c>capsGroup $Wing</c>. | |||
44 | * | |||
45 | * - <b> capsLoad</b> This is a name assigned to any geometric body where a load is applied. This attribute was separated from the <c>capsGroup</c> | |||
46 | * attribute to allow the user to define a local area to apply a load on without adding multiple <c>capsGroup</c> attributes. | |||
47 | * Recall that a string in ESP starts with a $. For example, attribute <c>capsLoad $force</c>. | |||
48 | * | |||
49 | * - <b> capsConstraint</b> This is a name assigned to any geometric body where a constraint/boundary condition is applied. | |||
50 | * This attribute was separated from the <c>capsGroup</c> attribute to allow the user to define a local area to apply a boundary condition | |||
51 | * without adding multiple <c>capsGroup</c> attributes. Recall that a string in ESP starts with a $. For example, attribute <c>capsConstraint $fixed</c>. | |||
52 | * | |||
53 | * - <b> capsIgnore</b> It is possible that there is a geometric body (or entity) that you do not want the MYSTRAN AIM to pay attention to when creating | |||
54 | * a finite element model. The capsIgnore attribute allows a body (or entity) to be in the geometry and ignored by the AIM. For example, | |||
55 | * because of limitations in OpenCASCADE a situation where two edges are overlapping may occur; capsIgnore allows the user to only | |||
56 | * pay attention to one of the overlapping edges. | |||
57 | * | |||
58 | * - <b> capsBound </b> This is used to mark surfaces on the structural grid in which data transfer with an external | |||
59 | * solver will take place. See \ref dataTransferMYSTRAN for additional details. | |||
60 | * | |||
61 | * | |||
62 | */ | |||
63 | ||||
64 | // No connections yet | |||
65 | /* - <b> capsConnect</b> This is a name assigned to any geometric body where the user wishes to create | |||
66 | * "fictitious" connections such as springs, dampers, and/or rigid body connections to. The user must manually specify | |||
67 | * the connection between two <c>capsConnect</c> entities using the "Connect" tuple (see \ref aimInputsMYSTRAN). | |||
68 | * Recall that a string in ESP starts with a $. For example, attribute <c>capsConnect $springStart</c>. | |||
69 | * | |||
70 | * - <b> capsConnectLink</b> Similar to <c>capsConnect</c>, this is a name assigned to any geometric body where | |||
71 | * the user wishes to create "fictitious" connections to. A connection is automatically made if a <c>capsConnectLink</c> | |||
72 | * matches a <c>capsConnect</c> group. Again further specifics of the connection are input using the "Connect" | |||
73 | * tuple (see \ref aimInputsMYSTRAN). Recall that a string in ESP starts with a $. | |||
74 | * For example, attribute <c>capsConnectLink $springEnd</c>. | |||
75 | */ | |||
76 | ||||
77 | #include <string.h> | |||
78 | #include <math.h> | |||
79 | #include "capsTypes.h" | |||
80 | #include "aimUtil.h" | |||
81 | ||||
82 | #include "meshUtils.h" | |||
83 | #include "miscUtils.h" | |||
84 | #include "feaUtils.h" | |||
85 | #include "nastranUtils.h" | |||
86 | #include "mystranUtils.h" | |||
87 | ||||
88 | #ifdef WIN32 | |||
89 | #define snprintf _snprintf | |||
90 | #define strcasecmp stricmp | |||
91 | #endif | |||
92 | ||||
93 | //#define DEBUG | |||
94 | ||||
95 | enum aimInputs | |||
96 | { | |||
97 | Proj_Name = 1, /* index is 1-based */ | |||
98 | Tess_Params, | |||
99 | Edge_Point_Min, | |||
100 | Edge_Point_Max, | |||
101 | Quad_Mesh, | |||
102 | Property, | |||
103 | Material, | |||
104 | Constraint, | |||
105 | Load, | |||
106 | Analysix, | |||
107 | Analysis_Type, | |||
108 | Support, | |||
109 | Mesh, | |||
110 | NUMINPUT = Mesh /* Total number of inputs */ | |||
111 | }; | |||
112 | ||||
113 | #define NUMOUTPUT4 4 | |||
114 | ||||
115 | ||||
116 | typedef struct { | |||
117 | // Project name | |||
118 | char *projectName; | |||
119 | ||||
120 | feaUnitsStruct units; // units system | |||
121 | ||||
122 | feaProblemStruct feaProblem; | |||
123 | ||||
124 | // Attribute to index map | |||
125 | mapAttrToIndexStruct attrMap; | |||
126 | ||||
127 | // Attribute to constraint index map | |||
128 | mapAttrToIndexStruct constraintMap; | |||
129 | ||||
130 | // Attribute to load index map | |||
131 | mapAttrToIndexStruct loadMap; | |||
132 | ||||
133 | /* | |||
134 | // Check to make sure data transfer is ok | |||
135 | int dataTransferCheck; | |||
136 | */ | |||
137 | ||||
138 | // Mesh holders | |||
139 | int numMesh; | |||
140 | meshStruct *feaMesh; | |||
141 | ||||
142 | } aimStorage; | |||
143 | ||||
144 | ||||
145 | static int initiate_aimStorage(aimStorage *mystranInstance) | |||
146 | { | |||
147 | ||||
148 | int status; | |||
149 | ||||
150 | // Set initial values for mystranInstance | |||
151 | mystranInstance->projectName = NULL((void*)0); | |||
152 | ||||
153 | // Mesh holders | |||
154 | mystranInstance->numMesh = 0; | |||
155 | mystranInstance->feaMesh = NULL((void*)0); | |||
156 | ||||
157 | /* | |||
158 | // Check to make sure data transfer is ok | |||
159 | mystranInstance->dataTransferCheck = (int) true; | |||
160 | */ | |||
161 | ||||
162 | status = initiate_feaUnitsStruct(&mystranInstance->units); | |||
163 | if (status != CAPS_SUCCESS0) return status; | |||
164 | ||||
165 | // Container for attribute to index map | |||
166 | status = initiate_mapAttrToIndexStruct(&mystranInstance->attrMap); | |||
167 | if (status != CAPS_SUCCESS0) return status; | |||
168 | ||||
169 | // Container for attribute to constraint index map | |||
170 | status = initiate_mapAttrToIndexStruct(&mystranInstance->constraintMap); | |||
171 | if (status != CAPS_SUCCESS0) return status; | |||
172 | ||||
173 | // Container for attribute to load index map | |||
174 | status = initiate_mapAttrToIndexStruct(&mystranInstance->loadMap); | |||
175 | if (status != CAPS_SUCCESS0) return status; | |||
176 | ||||
177 | status = initiate_feaProblemStruct(&mystranInstance->feaProblem); | |||
178 | if (status != CAPS_SUCCESS0) return status; | |||
179 | ||||
180 | return CAPS_SUCCESS0; | |||
181 | } | |||
182 | ||||
183 | ||||
184 | static int destroy_aimStorage(aimStorage *mystranInstance) | |||
185 | { | |||
186 | ||||
187 | int status; | |||
188 | int i; | |||
189 | ||||
190 | status = destroy_feaUnitsStruct(&mystranInstance->units); | |||
191 | if (status != CAPS_SUCCESS0) | |||
192 | printf("Error: Status %d during destroy_feaUnitsStruct!\n", status); | |||
193 | ||||
194 | // Attribute to index map | |||
195 | status = destroy_mapAttrToIndexStruct(&mystranInstance->attrMap); | |||
196 | if (status != CAPS_SUCCESS0) | |||
197 | printf("Error: Status %d during destroy_mapAttrToIndexStruct!\n", status); | |||
198 | ||||
199 | // Attribute to constraint index map | |||
200 | status = destroy_mapAttrToIndexStruct(&mystranInstance->constraintMap); | |||
201 | if (status != CAPS_SUCCESS0) | |||
202 | printf("Error: Status %d during destroy_mapAttrToIndexStruct!\n", status); | |||
203 | ||||
204 | // Attribute to load index map | |||
205 | status = destroy_mapAttrToIndexStruct(&mystranInstance->loadMap); | |||
206 | if (status != CAPS_SUCCESS0) | |||
207 | printf("Error: Status %d during destroy_mapAttrToIndexStruct!\n", status); | |||
208 | ||||
209 | // Cleanup meshes | |||
210 | if (mystranInstance->feaMesh != NULL((void*)0)) { | |||
211 | ||||
212 | for (i = 0; i < mystranInstance->numMesh; i++) { | |||
213 | status = destroy_meshStruct(&mystranInstance->feaMesh[i]); | |||
214 | if (status != CAPS_SUCCESS0) | |||
215 | printf("Error: Status %d during destroy_meshStruct!\n", status); | |||
216 | } | |||
217 | ||||
218 | AIM_FREE(mystranInstance->feaMesh){ EG_free(mystranInstance->feaMesh); mystranInstance->feaMesh = ((void*)0); }; | |||
219 | } | |||
220 | ||||
221 | mystranInstance->feaMesh = NULL((void*)0); | |||
222 | mystranInstance->numMesh = 0; | |||
223 | ||||
224 | // Destroy FEA problem structure | |||
225 | status = destroy_feaProblemStruct(&mystranInstance->feaProblem); | |||
226 | if (status != CAPS_SUCCESS0) | |||
227 | printf("Error: Status %d during destroy_feaProblemStruct!\n", status); | |||
228 | ||||
229 | // NULL projetName | |||
230 | mystranInstance->projectName = NULL((void*)0); | |||
231 | ||||
232 | return CAPS_SUCCESS0; | |||
233 | } | |||
234 | ||||
235 | ||||
236 | static int checkAndCreateMesh(void *aimInfo, aimStorage *mystranInstance) | |||
237 | { | |||
238 | // Function return flag | |||
239 | int status = CAPS_SUCCESS0; | |||
240 | int i, remesh = (int)true1; | |||
241 | ||||
242 | // Meshing related variables | |||
243 | double tessParam[3] = {0.025, 0.001, 15}; | |||
244 | int edgePointMin = 2; | |||
245 | int edgePointMax = 50; | |||
246 | int quadMesh = (int) false0; | |||
247 | ||||
248 | // Attribute to transfer map | |||
249 | mapAttrToIndexStruct transferMap; | |||
250 | ||||
251 | // Attribute to connect map | |||
252 | mapAttrToIndexStruct connectMap; | |||
253 | ||||
254 | // analysis input values | |||
255 | capsValue *TessParams; | |||
256 | capsValue *EdgePoint_Min; | |||
257 | capsValue *EdgePoint_Max; | |||
258 | capsValue *QuadMesh; | |||
259 | ||||
260 | for (i = 0; i < mystranInstance->numMesh; i++) { | |||
261 | remesh = remesh && (mystranInstance->feaMesh[i].egadsTess->oclass == EMPTY4); | |||
262 | } | |||
263 | if (remesh == (int) false0) return CAPS_SUCCESS0; | |||
264 | ||||
265 | // retrieve or create the mesh from fea_createMesh | |||
266 | status = aim_getValue(aimInfo, Tess_Params, ANALYSISIN, &TessParams); | |||
267 | if (status != CAPS_SUCCESS0) return status; | |||
268 | ||||
269 | status = aim_getValue(aimInfo, Edge_Point_Min, ANALYSISIN, &EdgePoint_Min); | |||
270 | if (status != CAPS_SUCCESS0) return status; | |||
271 | ||||
272 | status = aim_getValue(aimInfo, Edge_Point_Max, ANALYSISIN, &EdgePoint_Max); | |||
273 | if (status != CAPS_SUCCESS0) return status; | |||
274 | ||||
275 | status = aim_getValue(aimInfo, Quad_Mesh, ANALYSISIN, &QuadMesh); | |||
276 | if (status != CAPS_SUCCESS0) return status; | |||
277 | ||||
278 | if (TessParams != NULL((void*)0)) { | |||
279 | tessParam[0] = TessParams->vals.reals[0]; | |||
280 | tessParam[1] = TessParams->vals.reals[1]; | |||
281 | tessParam[2] = TessParams->vals.reals[2]; | |||
282 | } | |||
283 | ||||
284 | // Max and min number of points | |||
285 | if (EdgePoint_Min != NULL((void*)0) && EdgePoint_Min->nullVal != IsNull) { | |||
286 | edgePointMin = EdgePoint_Min->vals.integer; | |||
287 | if (edgePointMin < 2) { | |||
288 | AIM_ANALYSISIN_ERROR(aimInfo, Edge_Point_Min, "Edge_Point_Min = %d must be greater or equal to 2\n", edgePointMin){ aim_message(aimInfo, CERROR, Edge_Point_Min, "mystranAIM.c" , 288, __func__, "Edge_Point_Min = %d must be greater or equal to 2\n" , edgePointMin); }; | |||
289 | return CAPS_BADVALUE-311; | |||
290 | } | |||
291 | } | |||
292 | ||||
293 | if (EdgePoint_Max != NULL((void*)0) && EdgePoint_Max->nullVal != IsNull) { | |||
294 | edgePointMax = EdgePoint_Max->vals.integer; | |||
295 | if (edgePointMax < 2) { | |||
296 | AIM_ANALYSISIN_ERROR(aimInfo, Edge_Point_Max, "Edge_Point_Max = %d must be greater or equal to 2\n", edgePointMax){ aim_message(aimInfo, CERROR, Edge_Point_Max, "mystranAIM.c" , 296, __func__, "Edge_Point_Max = %d must be greater or equal to 2\n" , edgePointMax); }; | |||
297 | return CAPS_BADVALUE-311; | |||
298 | } | |||
299 | } | |||
300 | ||||
301 | if (edgePointMin >= 2 && edgePointMax >= 2 && edgePointMin > edgePointMax) { | |||
302 | AIM_ERROR (aimInfo, "Edge_Point_Max must be greater or equal Edge_Point_Min"){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 302, __func__ , "Edge_Point_Max must be greater or equal Edge_Point_Min"); }; | |||
303 | AIM_ADDLINE(aimInfo, "Edge_Point_Max = %d, Edge_Point_Min = %d\n",edgePointMax,edgePointMin){ aim_addLine(aimInfo, "Edge_Point_Max = %d, Edge_Point_Min = %d\n" ,edgePointMax,edgePointMin); }; | |||
304 | return CAPS_BADVALUE-311; | |||
305 | } | |||
306 | ||||
307 | if (QuadMesh != NULL((void*)0)) quadMesh = QuadMesh->vals.integer; | |||
308 | ||||
309 | status = initiate_mapAttrToIndexStruct(&transferMap); | |||
310 | if (status != CAPS_SUCCESS0) return status; | |||
311 | ||||
312 | status = initiate_mapAttrToIndexStruct(&connectMap); | |||
313 | if (status != CAPS_SUCCESS0) return status; | |||
314 | /*@-nullpass@*/ | |||
315 | status = fea_createMesh(aimInfo, | |||
316 | tessParam, | |||
317 | edgePointMin, | |||
318 | edgePointMax, | |||
319 | quadMesh, | |||
320 | &mystranInstance->attrMap, | |||
321 | &mystranInstance->constraintMap, | |||
322 | &mystranInstance->loadMap, | |||
323 | &transferMap, | |||
324 | &connectMap, | |||
325 | NULL((void*)0), | |||
326 | &mystranInstance->numMesh, | |||
327 | &mystranInstance->feaMesh, | |||
328 | &mystranInstance->feaProblem); | |||
329 | /*@+nullpass@*/ | |||
330 | if (status != CAPS_SUCCESS0) return status; | |||
331 | ||||
332 | status = destroy_mapAttrToIndexStruct(&transferMap); | |||
333 | if (status != CAPS_SUCCESS0) return status; | |||
334 | ||||
335 | status = destroy_mapAttrToIndexStruct(&connectMap); | |||
336 | if (status != CAPS_SUCCESS0) return status; | |||
337 | ||||
338 | return CAPS_SUCCESS0; | |||
339 | } | |||
340 | ||||
341 | ||||
342 | /* ********************** Exposed AIM Functions ***************************** */ | |||
343 | ||||
344 | int aimInitialize(int inst, /*@unused@*/ const char *unitSys, void *aimInfo, | |||
345 | /*@unused@*/ void **instStore, /*@unused@*/ int *major, | |||
346 | /*@unused@*/ int *minor, int *nIn, int *nOut, | |||
347 | int *nFields, char ***fnames, int **franks, int **fInOut) | |||
348 | { | |||
349 | int status = CAPS_SUCCESS0, *ints=NULL((void*)0), i; | |||
350 | char **strs=NULL((void*)0); | |||
351 | ||||
352 | aimStorage *mystranInstance=NULL((void*)0); | |||
353 | ||||
354 | #ifdef DEBUG | |||
355 | printf("mystranAIM/aimInitialize inst = %d!\n", inst); | |||
356 | #endif | |||
357 | ||||
358 | /* specify the number of analysis input and out "parameters" */ | |||
359 | *nIn = NUMINPUT; | |||
360 | *nOut = NUMOUTPUT4; | |||
361 | if (inst == -1) return CAPS_SUCCESS0; | |||
362 | ||||
363 | /* specify the field variables this analysis can generate and consume */ | |||
364 | *nFields = 4; | |||
365 | ||||
366 | /* specify the name of each field variable */ | |||
367 | AIM_ALLOC(strs, *nFields, char *, aimInfo, status){ if (strs != ((void*)0)) { status = -4; aim_status(aimInfo, status , "mystranAIM.c", 367, __func__, 1, "AIM_ALLOC: %s != NULL", "strs" ); goto cleanup; } size_t memorysize = *nFields; strs = (char * *) EG_alloc(memorysize*sizeof(char *)); if (strs == ((void *)0)) { status = -4; aim_status(aimInfo, status, "mystranAIM.c" , 367, __func__, 3, "AIM_ALLOC: %s size %zu type %s", "strs", memorysize, "char *"); goto cleanup; } }; | |||
368 | ||||
369 | strs[0] = EG_strdup("Displacement"); | |||
370 | strs[1] = EG_strdup("EigenVector"); | |||
371 | strs[2] = EG_strdup("EigenVector_#"); | |||
372 | strs[3] = EG_strdup("Pressure"); | |||
373 | for (i = 0; i < *nFields; i++) | |||
374 | if (strs[i] == NULL((void*)0)) { status = EGADS_MALLOC-4; goto cleanup; } | |||
375 | *fnames = strs; | |||
376 | ||||
377 | /* specify the dimension of each field variable */ | |||
378 | AIM_ALLOC(ints, *nFields, int, aimInfo, status){ if (ints != ((void*)0)) { status = -4; aim_status(aimInfo, status , "mystranAIM.c", 378, __func__, 1, "AIM_ALLOC: %s != NULL", "ints" ); goto cleanup; } size_t memorysize = *nFields; ints = (int * ) EG_alloc(memorysize*sizeof(int)); if (ints == ((void*)0)) { status = -4; aim_status(aimInfo, status, "mystranAIM.c", 378 , __func__, 3, "AIM_ALLOC: %s size %zu type %s", "ints", memorysize , "int"); goto cleanup; } }; | |||
379 | ints[0] = 3; | |||
380 | ints[1] = 3; | |||
381 | ints[2] = 3; | |||
382 | ints[3] = 1; | |||
383 | *franks = ints; | |||
384 | ints = NULL((void*)0); | |||
385 | ||||
386 | /* specify if a field is an input field or output field */ | |||
387 | AIM_ALLOC(ints, *nFields, int, aimInfo, status){ if (ints != ((void*)0)) { status = -4; aim_status(aimInfo, status , "mystranAIM.c", 387, __func__, 1, "AIM_ALLOC: %s != NULL", "ints" ); goto cleanup; } size_t memorysize = *nFields; ints = (int * ) EG_alloc(memorysize*sizeof(int)); if (ints == ((void*)0)) { status = -4; aim_status(aimInfo, status, "mystranAIM.c", 387 , __func__, 3, "AIM_ALLOC: %s size %zu type %s", "ints", memorysize , "int"); goto cleanup; } }; | |||
388 | ||||
389 | ints[0] = FieldOut; | |||
390 | ints[1] = FieldOut; | |||
391 | ints[2] = FieldOut; | |||
392 | ints[3] = FieldIn; | |||
393 | *fInOut = ints; | |||
394 | ints = NULL((void*)0); | |||
395 | ||||
396 | // Allocate mystranInstance | |||
397 | AIM_ALLOC(mystranInstance, 1, aimStorage, aimInfo, status){ if (mystranInstance != ((void*)0)) { status = -4; aim_status (aimInfo, status, "mystranAIM.c", 397, __func__, 1, "AIM_ALLOC: %s != NULL" , "mystranInstance"); goto cleanup; } size_t memorysize = 1; mystranInstance = (aimStorage *) EG_alloc(memorysize*sizeof(aimStorage)); if (mystranInstance == ((void*)0)) { status = -4; aim_status(aimInfo , status, "mystranAIM.c", 397, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "mystranInstance", memorysize, "aimStorage"); goto cleanup; } }; | |||
398 | *instStore = mystranInstance; | |||
399 | ||||
400 | // Initialize instance storage | |||
401 | status = initiate_aimStorage(mystranInstance); | |||
402 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 402, __func__, 0); goto cleanup; }; | |||
403 | ||||
404 | cleanup: | |||
405 | if (status != CAPS_SUCCESS0) { | |||
406 | /* release all possibly allocated memory on error */ | |||
407 | if (*fnames != NULL((void*)0)) | |||
408 | for (i = 0; i < *nFields; i++) AIM_FREE((*fnames)[i]){ EG_free((*fnames)[i]); (*fnames)[i] = ((void*)0); }; | |||
409 | AIM_FREE(*franks){ EG_free(*franks); *franks = ((void*)0); }; | |||
410 | AIM_FREE(*fInOut){ EG_free(*fInOut); *fInOut = ((void*)0); }; | |||
411 | AIM_FREE(*fnames){ EG_free(*fnames); *fnames = ((void*)0); }; | |||
412 | AIM_FREE(*instStore){ EG_free(*instStore); *instStore = ((void*)0); }; | |||
413 | *nFields = 0; | |||
414 | } | |||
415 | ||||
416 | return status; | |||
417 | } | |||
418 | ||||
419 | ||||
420 | int aimInputs(/*@unused@*/ void *instStore, /*@unused@*/ void *aimInfo, | |||
421 | int index, char **ainame, capsValue *defval) | |||
422 | { | |||
423 | /*! \page aimInputsMYSTRAN AIM Inputs | |||
424 | * The following list outlines the MYSTRAN inputs along with their default value available | |||
425 | * through the AIM interface. Unless noted these values will be not be linked to | |||
426 | * any parent AIMs with variables of the same name. | |||
427 | */ | |||
428 | int status = CAPS_SUCCESS0; | |||
429 | ||||
430 | #ifdef DEBUG | |||
431 | printf(" mystranAIM/aimInputs index = %d!\n", index); | |||
432 | #endif | |||
433 | ||||
434 | *ainame = NULL((void*)0); | |||
435 | ||||
436 | // MYSTRAN Inputs | |||
437 | if (index == Proj_Name) { | |||
438 | *ainame = EG_strdup("Proj_Name"); | |||
439 | defval->type = String; | |||
440 | defval->nullVal = NotNull; | |||
441 | defval->vals.string = EG_strdup("mystran_CAPS"); | |||
442 | defval->lfixed = Change; | |||
443 | ||||
444 | /*! \page aimInputsMYSTRAN | |||
445 | * - <B> Proj_Name = "mystran_CAPS"</B> <br> | |||
446 | * This corresponds to the project name used for file naming. | |||
447 | */ | |||
448 | ||||
449 | } else if (index == Tess_Params) { | |||
450 | *ainame = EG_strdup("Tess_Params"); | |||
451 | defval->type = Double; | |||
452 | defval->dim = Vector; | |||
453 | defval->nrow = 3; | |||
454 | defval->ncol = 1; | |||
455 | defval->units = NULL((void*)0); | |||
456 | defval->lfixed = Fixed; | |||
457 | defval->vals.reals = (double *) EG_alloc(defval->nrow*sizeof(double)); | |||
458 | if (defval->vals.reals != NULL((void*)0)) { | |||
459 | defval->vals.reals[0] = 0.025; | |||
460 | defval->vals.reals[1] = 0.001; | |||
461 | defval->vals.reals[2] = 15.00; | |||
462 | } else return EGADS_MALLOC-4; | |||
463 | ||||
464 | /*! \page aimInputsMYSTRAN | |||
465 | * - <B> Tess_Params = [0.025, 0.001, 15.0]</B> <br> | |||
466 | * Body tessellation parameters used when creating a boundary element model. | |||
467 | * Tess_Params[0] and Tess_Params[1] get scaled by the bounding | |||
468 | * box of the body. (From the EGADS manual) A set of 3 parameters that drive the EDGE discretization | |||
469 | * and the FACE triangulation. The first is the maximum length of an EDGE segment or triangle side | |||
470 | * (in physical space). A zero is flag that allows for any length. The second is a curvature-based | |||
471 | * value that looks locally at the deviation between the centroid of the discrete object and the | |||
472 | * underlying geometry. Any deviation larger than the input value will cause the tessellation to | |||
473 | * be enhanced in those regions. The third is the maximum interior dihedral angle (in degrees) | |||
474 | * between triangle facets (or Edge segment tangents for a WIREBODY tessellation), note that a | |||
475 | * zero ignores this phase | |||
476 | */ | |||
477 | ||||
478 | } else if (index == Edge_Point_Min) { | |||
479 | *ainame = EG_strdup("Edge_Point_Min"); | |||
480 | defval->type = Integer; | |||
481 | defval->vals.integer = 2; | |||
482 | defval->lfixed = Fixed; | |||
483 | defval->nrow = 1; | |||
484 | defval->ncol = 1; | |||
485 | defval->nullVal = NotNull; | |||
486 | ||||
487 | /*! \page aimInputsMYSTRAN | |||
488 | * - <B> Edge_Point_Min = 2</B> <br> | |||
489 | * Minimum number of points on an edge including end points to use when creating a surface mesh (min 2). | |||
490 | */ | |||
491 | ||||
492 | } else if (index == Edge_Point_Max) { | |||
493 | *ainame = EG_strdup("Edge_Point_Max"); | |||
494 | defval->type = Integer; | |||
495 | defval->vals.integer = 50; | |||
496 | defval->lfixed = Fixed; | |||
497 | defval->nrow = 1; | |||
498 | defval->ncol = 1; | |||
499 | defval->nullVal = NotNull; | |||
500 | ||||
501 | /*! \page aimInputsMYSTRAN | |||
502 | * - <B> Edge_Point_Max = 50</B> <br> | |||
503 | * Maximum number of points on an edge including end points to use when creating a surface mesh (min 2). | |||
504 | */ | |||
505 | ||||
506 | } else if (index == Quad_Mesh) { | |||
507 | *ainame = EG_strdup("Quad_Mesh"); | |||
508 | defval->type = Boolean; | |||
509 | defval->vals.integer = (int) false0; | |||
510 | ||||
511 | /*! \page aimInputsMYSTRAN | |||
512 | * - <B> Quad_Mesh = False</B> <br> | |||
513 | * Create a quadratic mesh on four edge faces when creating the boundary element model. | |||
514 | */ | |||
515 | ||||
516 | } else if (index == Property) { | |||
517 | *ainame = EG_strdup("Property"); | |||
518 | defval->type = Tuple; | |||
519 | defval->nullVal = IsNull; | |||
520 | //defval->units = NULL; | |||
521 | defval->lfixed = Change; | |||
522 | defval->vals.tuple = NULL((void*)0); | |||
523 | defval->dim = Vector; | |||
524 | ||||
525 | /*! \page aimInputsMYSTRAN | |||
526 | * - <B> Property = NULL</B> <br> | |||
527 | * Property tuple used to input property information for the model, see \ref feaProperty for additional details. | |||
528 | */ | |||
529 | } else if (index == Material) { | |||
530 | *ainame = EG_strdup("Material"); | |||
531 | defval->type = Tuple; | |||
532 | defval->nullVal = IsNull; | |||
533 | //defval->units = NULL; | |||
534 | defval->lfixed = Change; | |||
535 | defval->vals.tuple = NULL((void*)0); | |||
536 | defval->dim = Vector; | |||
537 | ||||
538 | /*! \page aimInputsMYSTRAN | |||
539 | * - <B> Material = NULL</B> <br> | |||
540 | * Material tuple used to input material information for the model, see \ref feaMaterial for additional details. | |||
541 | */ | |||
542 | } else if (index == Constraint) { | |||
543 | *ainame = EG_strdup("Constraint"); | |||
544 | defval->type = Tuple; | |||
545 | defval->nullVal = IsNull; | |||
546 | //defval->units = NULL; | |||
547 | defval->lfixed = Change; | |||
548 | defval->vals.tuple = NULL((void*)0); | |||
549 | defval->dim = Vector; | |||
550 | ||||
551 | /*! \page aimInputsMYSTRAN | |||
552 | * - <B> Constraint = NULL</B> <br> | |||
553 | * Constraint tuple used to input constraint information for the model, see \ref feaConstraint for additional details. | |||
554 | */ | |||
555 | } else if (index == Load) { | |||
556 | *ainame = EG_strdup("Load"); | |||
557 | defval->type = Tuple; | |||
558 | defval->nullVal = IsNull; | |||
559 | //defval->units = NULL; | |||
560 | defval->lfixed = Change; | |||
561 | defval->vals.tuple = NULL((void*)0); | |||
562 | defval->dim = Vector; | |||
563 | ||||
564 | /*! \page aimInputsMYSTRAN | |||
565 | * - <B> Load = NULL</B> <br> | |||
566 | * Load tuple used to input load information for the model, see \ref feaLoad for additional details. | |||
567 | */ | |||
568 | } else if (index == Analysix) { | |||
569 | *ainame = EG_strdup("Analysis"); | |||
570 | defval->type = Tuple; | |||
571 | defval->nullVal = IsNull; | |||
572 | //defval->units = NULL; | |||
573 | defval->lfixed = Change; | |||
574 | defval->vals.tuple = NULL((void*)0); | |||
575 | defval->dim = Vector; | |||
576 | ||||
577 | /*! \page aimInputsMYSTRAN | |||
578 | * - <B> Analysis = NULL</B> <br> | |||
579 | * Analysis tuple used to input analysis/case information for the model, see \ref feaAnalysis for additional details. | |||
580 | */ | |||
581 | } else if (index == Analysis_Type) { | |||
582 | *ainame = EG_strdup("Analysis_Type"); | |||
583 | defval->type = String; | |||
584 | defval->nullVal = NotNull; | |||
585 | defval->vals.string = EG_strdup("Modal"); | |||
586 | defval->lfixed = Change; | |||
587 | ||||
588 | /*! \page aimInputsMYSTRAN | |||
589 | * - <B> Analysis_Type = "Modal"</B> <br> | |||
590 | * Type of analysis to generate files for, options include "Modal", "Static", and "Craig-Bampton". | |||
591 | */ | |||
592 | } else if (index == Support) { | |||
593 | *ainame = EG_strdup("Support"); | |||
594 | defval->type = Tuple; | |||
595 | defval->nullVal = IsNull; | |||
596 | //defval->units = NULL; | |||
597 | defval->lfixed = Change; | |||
598 | defval->vals.tuple = NULL((void*)0); | |||
599 | defval->dim = Vector; | |||
600 | ||||
601 | /*! \page aimInputsMYSTRAN | |||
602 | * - <B> Support = NULL</B> <br> | |||
603 | * Support tuple used to input support information for the model, see \ref feaSupport for additional details. | |||
604 | */ | |||
605 | ||||
606 | } else if (index == Mesh) { | |||
607 | *ainame = AIM_NAME(Mesh)EG_strdup("Mesh"); | |||
608 | defval->type = Pointer; | |||
609 | defval->dim = Vector; | |||
610 | defval->lfixed = Change; | |||
611 | defval->sfixed = Change; | |||
612 | defval->vals.AIMptr = NULL((void*)0); | |||
613 | defval->nullVal = IsNull; | |||
614 | AIM_STRDUP(defval->units, "meshStruct", aimInfo, status){ if (defval->units != ((void*)0)) { status = -4; aim_status (aimInfo, status, "mystranAIM.c", 614, __func__, 1, "AIM_STRDUP: %s != NULL!" , "defval->units"); goto cleanup; } defval->units = EG_strdup ("meshStruct"); if (defval->units == ((void*)0)) { status = -4; aim_status(aimInfo, status, "mystranAIM.c", 614, __func__ , 2, "AIM_STRDUP: %s %s", "defval->units", "meshStruct"); goto cleanup; } }; | |||
615 | ||||
616 | /*! \page aimInputsMYSTRAN | |||
617 | * - <B>Mesh = NULL</B> <br> | |||
618 | * A Mesh link. | |||
619 | */ | |||
620 | ||||
621 | } else { | |||
622 | status = CAPS_BADINDEX-304; | |||
623 | AIM_STATUS(aimInfo, status, "Unknown input index %d!", index)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 623, __func__, 2, "Unknown input index %d!", index); goto cleanup ; }; | |||
624 | } | |||
625 | ||||
626 | AIM_NOTNULL(*ainame, aimInfo, status){ if (*ainame == ((void*)0)) { status = -307; aim_status(aimInfo , status, "mystranAIM.c", 626, __func__, 1, "%s == NULL!", "*ainame" ); goto cleanup; } }; | |||
627 | ||||
628 | cleanup: | |||
629 | if (status != CAPS_SUCCESS0) AIM_FREE(*ainame){ EG_free(*ainame); *ainame = ((void*)0); }; | |||
630 | return status; | |||
631 | } | |||
632 | ||||
633 | ||||
634 | // ********************** AIM Function Break ***************************** | |||
635 | int aimUpdateState(void *instStore, void *aimInfo, | |||
636 | capsValue *aimInputs) | |||
637 | { | |||
638 | int status; // Function return status | |||
639 | ||||
640 | aimStorage *mystranInstance; | |||
641 | ||||
642 | mystranInstance = (aimStorage *) instStore; | |||
643 | AIM_NOTNULL(aimInputs, aimInfo, status){ if (aimInputs == ((void*)0)) { status = -307; aim_status(aimInfo , status, "mystranAIM.c", 643, __func__, 1, "%s == NULL!", "aimInputs" ); goto cleanup; } }; | |||
644 | ||||
645 | // Get project name | |||
646 | mystranInstance->projectName = aimInputs[Proj_Name-1].vals.string; | |||
647 | ||||
648 | // Check and generate/retrieve the mesh | |||
649 | status = checkAndCreateMesh(aimInfo, mystranInstance); | |||
650 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 650, __func__, 0); goto cleanup; }; | |||
651 | ||||
652 | // Note: Setting order is important here. | |||
653 | // 1. Materials should be set before properties. | |||
654 | // 2. Coordinate system should be set before mesh and loads | |||
655 | // 3. Mesh should be set before loads and constraints | |||
656 | // 4. Constraints and loads should be set before analysis | |||
657 | ||||
658 | // Set material properties | |||
659 | if (aimInputs[Material-1].nullVal == NotNull) { | |||
660 | status = fea_getMaterial(aimInfo, | |||
661 | aimInputs[Material-1].length, | |||
662 | aimInputs[Material-1].vals.tuple, | |||
663 | &mystranInstance->units, | |||
664 | &mystranInstance->feaProblem.numMaterial, | |||
665 | &mystranInstance->feaProblem.feaMaterial); | |||
666 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 666, __func__, 0); goto cleanup; }; | |||
667 | } else printf("\nLoad tuple is NULL - No materials set\n"); | |||
668 | ||||
669 | // Set property properties | |||
670 | if (aimInputs[Property-1].nullVal == NotNull) { | |||
671 | status = fea_getProperty(aimInfo, | |||
672 | aimInputs[Property-1].length, | |||
673 | aimInputs[Property-1].vals.tuple, | |||
674 | &mystranInstance->attrMap, | |||
675 | &mystranInstance->units, | |||
676 | &mystranInstance->feaProblem); | |||
677 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 677, __func__, 0); goto cleanup; }; | |||
678 | } else printf("\nProperty tuple is NULL - No properties set\n"); | |||
679 | ||||
680 | // Set constraint properties | |||
681 | if (aimInputs[Constraint-1].nullVal == NotNull) { | |||
682 | status = fea_getConstraint(aimInputs[Constraint-1].length, | |||
683 | aimInputs[Constraint-1].vals.tuple, | |||
684 | &mystranInstance->constraintMap, | |||
685 | &mystranInstance->feaProblem); | |||
686 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 686, __func__, 0); goto cleanup; }; | |||
687 | } else printf("\nConstraint tuple is NULL - No constraints applied\n"); | |||
688 | ||||
689 | // Set support properties | |||
690 | if (aimInputs[Support-1].nullVal == NotNull) { | |||
691 | status = fea_getSupport(aimInputs[Support-1].length, | |||
692 | aimInputs[Support-1].vals.tuple, | |||
693 | &mystranInstance->constraintMap, | |||
694 | &mystranInstance->feaProblem); | |||
695 | if (status != CAPS_SUCCESS0) return status; | |||
696 | } else printf("Support tuple is NULL - No supports applied\n"); | |||
697 | ||||
698 | // Set load properties | |||
699 | if (aimInputs[Load-1].nullVal == NotNull) { | |||
700 | status = fea_getLoad(aimInputs[Load-1].length, | |||
701 | aimInputs[Load-1].vals.tuple, | |||
702 | &mystranInstance->loadMap, | |||
703 | &mystranInstance->feaProblem); | |||
704 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 704, __func__, 0); goto cleanup; }; | |||
705 | } else printf("\nLoad tuple is NULL - No loads applied\n"); | |||
706 | ||||
707 | // Set analysis settings | |||
708 | if (aimInputs[Analysix-1].nullVal == NotNull) { | |||
709 | status = fea_getAnalysis(aimInputs[Analysix-1].length, | |||
710 | aimInputs[Analysix-1].vals.tuple, | |||
711 | &mystranInstance->feaProblem); | |||
712 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 712, __func__, 0); goto cleanup; }; // It ok to not have an analysis tuple | |||
713 | } else printf("\nAnalysis tuple is NULL\n"); | |||
714 | ||||
715 | status = CAPS_SUCCESS0; | |||
716 | cleanup: | |||
717 | return status; | |||
718 | } | |||
719 | ||||
720 | ||||
721 | // ********************** AIM Function Break ***************************** | |||
722 | int aimPreAnalysis(const void *instStore, void *aimInfo, capsValue *aimInputs) | |||
723 | { | |||
724 | ||||
725 | int i, j, k; // Indexing | |||
726 | ||||
727 | int status; // Status return | |||
728 | ||||
729 | int found; // Boolean operator | |||
730 | ||||
731 | int *tempIntegerArray = NULL((void*)0); // Temporary array to store a list of integers | |||
732 | ||||
733 | // Analyis information | |||
734 | char *analysisType = NULL((void*)0); | |||
735 | ||||
736 | // File IO | |||
737 | char filename[PATH_MAX4096]; // Output file name | |||
738 | FILE *fp = NULL((void*)0); // Output file pointer | |||
739 | ||||
740 | const aimStorage *mystranInstance; | |||
741 | ||||
742 | // Load information | |||
743 | feaLoadStruct *feaLoad = NULL((void*)0); // size = [numLoad] | |||
| ||||
744 | ||||
745 | mystranInstance = (const aimStorage *) instStore; | |||
746 | AIM_NOTNULL(aimInputs, aimInfo, status){ if (aimInputs == ((void*)0)) { status = -307; aim_status(aimInfo , status, "mystranAIM.c", 746, __func__, 1, "%s == NULL!", "aimInputs" ); goto cleanup; } }; | |||
747 | ||||
748 | if (mystranInstance->feaProblem.numLoad > 0) { | |||
749 | AIM_ALLOC(feaLoad, mystranInstance->feaProblem.numLoad, feaLoadStruct, aimInfo, status){ if (feaLoad != ((void*)0)) { status = -4; aim_status(aimInfo , status, "mystranAIM.c", 749, __func__, 1, "AIM_ALLOC: %s != NULL" , "feaLoad"); goto cleanup; } size_t memorysize = mystranInstance ->feaProblem.numLoad; feaLoad = (feaLoadStruct *) EG_alloc (memorysize*sizeof(feaLoadStruct)); if (feaLoad == ((void*)0) ) { status = -4; aim_status(aimInfo, status, "mystranAIM.c", 749 , __func__, 3, "AIM_ALLOC: %s size %zu type %s", "feaLoad", memorysize , "feaLoadStruct"); goto cleanup; } }; | |||
750 | for (i = 0; i < mystranInstance->feaProblem.numLoad; i++) initiate_feaLoadStruct(&feaLoad[i]); | |||
751 | for (i = 0; i < mystranInstance->feaProblem.numLoad; i++) { | |||
752 | status = copy_feaLoadStruct(aimInfo, &mystranInstance->feaProblem.feaLoad[i], &feaLoad[i]); | |||
753 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 753, __func__, 0); goto cleanup; }; | |||
754 | ||||
755 | if (feaLoad[i].loadType == PressureExternal) { | |||
756 | ||||
757 | // Transfer external pressures from the AIM discrObj | |||
758 | status = fea_transferExternalPressure(aimInfo, | |||
759 | &mystranInstance->feaProblem.feaMesh, | |||
760 | &feaLoad[i]); | |||
761 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 761, __func__, 0); goto cleanup; }; | |||
762 | } | |||
763 | } | |||
764 | } | |||
765 | ||||
766 | // Write Nastran Mesh | |||
767 | status = mesh_writeNASTRAN(aimInfo, | |||
768 | mystranInstance->projectName, | |||
769 | 1, | |||
770 | &mystranInstance->feaProblem.feaMesh, | |||
771 | mystranInstance->feaProblem.feaFileFormat.gridFileType, | |||
772 | 1.0); | |||
773 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 773, __func__, 0); goto cleanup; }; | |||
774 | ||||
775 | // Write mystran input file | |||
776 | strcpy(filename, mystranInstance->projectName); | |||
777 | strcat(filename, ".dat"); | |||
778 | ||||
779 | printf("\nWriting MYSTRAN instruction file....\n"); | |||
780 | fp = aim_fopen(aimInfo, filename, "w"); | |||
781 | if (fp == NULL((void*)0)) { | |||
782 | AIM_ERROR(aimInfo, "Unable to open file: %s\n", filename){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 782, __func__ , "Unable to open file: %s\n", filename); }; | |||
783 | status = CAPS_IOERR-332; | |||
784 | goto cleanup; | |||
785 | } | |||
786 | ||||
787 | //////////////// Executive control //////////////// | |||
788 | fprintf(fp, "ID CAPS generated Problem FOR MYSTRAN\n"); | |||
789 | ||||
790 | // Analysis type | |||
791 | analysisType = aimInputs[Analysis_Type-1].vals.string; | |||
792 | ||||
793 | if (strcasecmp(analysisType, "Modal") == 0) fprintf(fp, "SOL 3\n"); | |||
794 | else if(strcasecmp(analysisType, "Static") == 0) fprintf(fp, "SOL 1\n"); | |||
795 | else if(strcasecmp(analysisType, "Craig-Bampton") == 0) fprintf(fp, "SOL 31\n"); | |||
796 | else { | |||
797 | AIM_ERROR(aimInfo, "Unrecognized \"Analysis_Type\", %s", analysisType){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 797, __func__ , "Unrecognized \"Analysis_Type\", %s", analysisType); }; | |||
798 | status = CAPS_BADVALUE-311; | |||
799 | goto cleanup; | |||
800 | } | |||
801 | ||||
802 | if (strcasecmp(analysisType, "Modal") == 0) fprintf(fp, "OUTPUT4 EIGEN_VAL, EIGEN_VEC, GEN_MASS, , // -1/21 $\n"); // Binary output of eigenvalues and vectors | |||
803 | ||||
804 | fprintf(fp, "CEND\n\n"); | |||
805 | ||||
806 | //////////////// Case control //////////////// | |||
807 | ||||
808 | // Write output request information | |||
809 | fprintf(fp, "DISP = ALL\n"); // Output all displacements | |||
810 | ||||
811 | if(strcasecmp(analysisType, "Static") == 0) fprintf(fp, "STRE = ALL\n"); // Output all stress | |||
812 | ||||
813 | if(strcasecmp(analysisType, "Static") == 0) fprintf(fp, "STRA = ALL\n"); // Output all strain | |||
814 | ||||
815 | //fprintf(fp, "ELDATA(6,PRINT) = ALL\n"); | |||
816 | ||||
817 | // Check thermal load - currently only a single thermal load is supported - also it only works for the global level - no subcase | |||
818 | found = (int) false0; | |||
819 | for (i = 0; i < mystranInstance->feaProblem.numLoad; i++) { | |||
820 | ||||
821 | if (feaLoad[i].loadType != Thermal) continue; | |||
| ||||
822 | ||||
823 | if (found == (int) true1) { | |||
824 | AIM_ERROR(aimInfo, "More than 1 Thermal load found - mystranAIM does NOT currently doesn't support multiple thermal loads!"){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 824, __func__ , "More than 1 Thermal load found - mystranAIM does NOT currently doesn't support multiple thermal loads!" ); }; | |||
825 | status = CAPS_BADVALUE-311; | |||
826 | goto cleanup; | |||
827 | } | |||
828 | ||||
829 | found = (int) true1; | |||
830 | ||||
831 | fprintf(fp, "TEMPERATURE = %d\n", | |||
832 | feaLoad[i].loadID); | |||
833 | } | |||
834 | ||||
835 | // Write constraint information | |||
836 | if (mystranInstance->feaProblem.numConstraint != 0) { | |||
837 | fprintf(fp, "SPC = %d\n", mystranInstance->feaProblem.numConstraint+1); | |||
838 | } else { | |||
839 | printf("Warning: No constraints specified for job!!!!\n"); | |||
840 | } | |||
841 | ||||
842 | // Modal analysis - only | |||
843 | // If modal - we are only going to use the first analysis structure we come across that has its type as modal | |||
844 | if (strcasecmp(analysisType, "Modal") == 0) { | |||
845 | ||||
846 | // Look through analysis structures for a modal one | |||
847 | found = (int) false0; | |||
848 | for (i = 0; i < mystranInstance->feaProblem.numAnalysis; i++) { | |||
849 | if (mystranInstance->feaProblem.feaAnalysis[i].analysisType == Modal) { | |||
850 | found = (int) true1; | |||
851 | break; | |||
852 | } | |||
853 | } | |||
854 | ||||
855 | // Write out analysis ID if a modal analysis structure was found | |||
856 | if (found == (int) true1) { | |||
857 | fprintf(fp, "METHOD = %d\n", | |||
858 | mystranInstance->feaProblem.feaAnalysis[i].analysisID); | |||
859 | } else { | |||
860 | printf("Warning: No eigenvalue analysis information specified in \"Analysis\" tuple, though " | |||
861 | "AIM input \"Analysis_Type\" is set to \"Modal\"!!!!\n"); | |||
862 | status = CAPS_NOTFOUND-303; | |||
863 | goto cleanup; | |||
864 | } | |||
865 | ||||
866 | } | |||
867 | // Static analysis - only | |||
868 | if (strcasecmp(analysisType, "Static") == 0) { | |||
869 | ||||
870 | // If we have multiple analysis structures | |||
871 | if (mystranInstance->feaProblem.numAnalysis != 0) { | |||
872 | ||||
873 | // Write subcase information if multiple analysis tuples were provide | |||
874 | for (i = 0; i < mystranInstance->feaProblem.numAnalysis; i++) { | |||
875 | ||||
876 | if (mystranInstance->feaProblem.feaAnalysis[i].analysisType == Static) { | |||
877 | fprintf(fp, "SUBCASE %d\n", i); | |||
878 | fprintf(fp, "\tLABEL %s\n", | |||
879 | mystranInstance->feaProblem.feaAnalysis[i].name); | |||
880 | ||||
881 | // Write loads for sub-case | |||
882 | if (mystranInstance->feaProblem.numLoad > 0) { | |||
883 | fprintf(fp, "\tLOAD = %d\n", | |||
884 | mystranInstance->feaProblem.numLoad+i+1); | |||
885 | } | |||
886 | ||||
887 | // Issue some warnings regarding loads if necessary | |||
888 | if (mystranInstance->feaProblem.feaAnalysis[i].numLoad == 0 && | |||
889 | mystranInstance->feaProblem.numLoad > 0) { | |||
890 | printf("Warning: No loads specified for static case %s, assuming " | |||
891 | "all loads are applied!!!!\n", | |||
892 | mystranInstance->feaProblem.feaAnalysis[i].name); | |||
893 | } else if (mystranInstance->feaProblem.numLoad == 0) { | |||
894 | printf("Warning: No loads specified for static case %s!!!!\n", | |||
895 | mystranInstance->feaProblem.feaAnalysis[i].name); | |||
896 | } | |||
897 | } | |||
898 | } | |||
899 | ||||
900 | } else { // // If no sub-cases | |||
901 | ||||
902 | if (mystranInstance->feaProblem.numLoad > 0) { | |||
903 | fprintf(fp, "LOAD = %d\n", mystranInstance->feaProblem.numLoad+1); | |||
904 | } else { | |||
905 | printf("Warning: No loads specified for static a job!!!!\n"); | |||
906 | } | |||
907 | } | |||
908 | } | |||
909 | ||||
910 | //////////////// Bulk data //////////////// | |||
911 | fprintf(fp, "\nBEGIN BULK\n"); | |||
912 | ||||
913 | // Turn off auto SPC | |||
914 | //fprintf(fp, "%-8s %7s %7s\n", "PARAM", "AUTOSPC", "N"); | |||
915 | ||||
916 | //fprintf(fp, "%-8s %7s %7d\n", "PARAM", "PRTOU4", 1); | |||
917 | //fprintf(fp, "%-8s %7s %7d\n", "PARAM", "PRTDLR", 1); | |||
918 | ||||
919 | //fprintf(fp, "%-8s %7s %7d\n", "PARAM", "PRTDOF", 1); | |||
920 | ||||
921 | //fprintf(fp, "%-8s %7d %7d\n", "DEBUG", 183, 1); | |||
922 | // Turn on FEMAP | |||
923 | //fprintf(fp, "%-8s %7s %7d\n", "PARAM", "POST", -1); | |||
924 | ||||
925 | // Analysis Cards - Eigenvalue included, as well as combined load | |||
926 | if (mystranInstance->feaProblem.numAnalysis != 0) { | |||
927 | ||||
928 | for (i = 0; i < mystranInstance->feaProblem.numAnalysis; i++) { | |||
929 | ||||
930 | status = nastran_writeAnalysisCard(fp, | |||
931 | &mystranInstance->feaProblem.feaAnalysis[i], | |||
932 | &mystranInstance->feaProblem.feaFileFormat); | |||
933 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 933, __func__, 0); goto cleanup; }; | |||
934 | ||||
935 | if (mystranInstance->feaProblem.feaAnalysis[i].numLoad != 0) { | |||
936 | ||||
937 | status = nastran_writeLoadADDCard(fp, | |||
938 | mystranInstance->feaProblem.numLoad+i+1, | |||
939 | mystranInstance->feaProblem.feaAnalysis[i].numLoad, | |||
940 | mystranInstance->feaProblem.feaAnalysis[i].loadSetID, | |||
941 | feaLoad, | |||
942 | &mystranInstance->feaProblem.feaFileFormat); | |||
943 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 943, __func__, 0); goto cleanup; }; | |||
944 | ||||
945 | } else { // If no loads for an individual analysis are specified assume that all loads should be applied | |||
946 | ||||
947 | if (feaLoad != NULL((void*)0)) { | |||
948 | ||||
949 | // Ignore thermal loads | |||
950 | k = 0; | |||
951 | for (j = 0; j < mystranInstance->feaProblem.numLoad; j++) { | |||
952 | if (feaLoad[j].loadType == Thermal) continue; | |||
953 | k += 1; | |||
954 | } | |||
955 | ||||
956 | if (k != 0) { | |||
957 | // Create a temporary list of load IDs | |||
958 | tempIntegerArray = (int *) EG_alloc(k*sizeof(int)); | |||
959 | if (tempIntegerArray == NULL((void*)0)) { | |||
960 | status = EGADS_MALLOC-4; | |||
961 | goto cleanup; | |||
962 | } | |||
963 | ||||
964 | k = 0; | |||
965 | for (j = 0; j < mystranInstance->feaProblem.numLoad; j++) { | |||
966 | ||||
967 | if (feaLoad[j].loadType == Thermal) continue; | |||
968 | tempIntegerArray[k] = feaLoad[j].loadID; | |||
969 | ||||
970 | k += 1; | |||
971 | } | |||
972 | ||||
973 | // Write combined load card | |||
974 | status = nastran_writeLoadADDCard(fp, | |||
975 | mystranInstance->feaProblem.numLoad+i+1, | |||
976 | k, | |||
977 | tempIntegerArray, | |||
978 | feaLoad, | |||
979 | &mystranInstance->feaProblem.feaFileFormat); | |||
980 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 980, __func__, 0); goto cleanup; }; | |||
981 | ||||
982 | // Free temporary load ID list | |||
983 | if (tempIntegerArray != NULL((void*)0)) EG_free(tempIntegerArray); | |||
984 | tempIntegerArray = NULL((void*)0); | |||
985 | } | |||
986 | } | |||
987 | } | |||
988 | } | |||
989 | ||||
990 | } else { // If there aren't any analysis structures just write a single combined load card | |||
991 | ||||
992 | // Combined loads | |||
993 | if (feaLoad != NULL((void*)0)) { | |||
994 | ||||
995 | // Ignore thermal loads | |||
996 | k = 0; | |||
997 | for (j = 0; j < mystranInstance->feaProblem.numLoad; j++) { | |||
998 | if (feaLoad[j].loadType == Thermal) continue; | |||
999 | k += 1; | |||
1000 | } | |||
1001 | ||||
1002 | if (k != 0) { | |||
1003 | // Create a temporary list of load IDs | |||
1004 | tempIntegerArray = (int *) EG_alloc(k*sizeof(int)); | |||
1005 | if (tempIntegerArray == NULL((void*)0)) { | |||
1006 | status = EGADS_MALLOC-4; | |||
1007 | goto cleanup; | |||
1008 | } | |||
1009 | ||||
1010 | k = 0; | |||
1011 | for (j = 0; j < mystranInstance->feaProblem.numLoad; j++) { | |||
1012 | ||||
1013 | if (feaLoad[j].loadType == Thermal) continue; | |||
1014 | tempIntegerArray[k] = feaLoad[j].loadID; | |||
1015 | ||||
1016 | k += 1; | |||
1017 | } | |||
1018 | ||||
1019 | // Write combined load card | |||
1020 | status = nastran_writeLoadADDCard(fp, | |||
1021 | mystranInstance->feaProblem.numLoad+1, | |||
1022 | k, | |||
1023 | tempIntegerArray, | |||
1024 | feaLoad, | |||
1025 | &mystranInstance->feaProblem.feaFileFormat); | |||
1026 | ||||
1027 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1027, __func__, 0); goto cleanup; }; | |||
1028 | ||||
1029 | // Free temporary load ID list | |||
1030 | AIM_FREE(tempIntegerArray){ EG_free(tempIntegerArray); tempIntegerArray = ((void*)0); }; | |||
1031 | } | |||
1032 | } | |||
1033 | } | |||
1034 | ||||
1035 | // Combined constraints | |||
1036 | if (mystranInstance->feaProblem.numConstraint != 0) { | |||
1037 | ||||
1038 | // Create a temporary list of constraint IDs | |||
1039 | AIM_ALLOC(tempIntegerArray, mystranInstance->feaProblem.numConstraint, int, aimInfo, status){ if (tempIntegerArray != ((void*)0)) { status = -4; aim_status (aimInfo, status, "mystranAIM.c", 1039, __func__, 1, "AIM_ALLOC: %s != NULL" , "tempIntegerArray"); goto cleanup; } size_t memorysize = mystranInstance ->feaProblem.numConstraint; tempIntegerArray = (int *) EG_alloc (memorysize*sizeof(int)); if (tempIntegerArray == ((void*)0)) { status = -4; aim_status(aimInfo, status, "mystranAIM.c", 1039 , __func__, 3, "AIM_ALLOC: %s size %zu type %s", "tempIntegerArray" , memorysize, "int"); goto cleanup; } }; | |||
1040 | ||||
1041 | for (i = 0; i < mystranInstance->feaProblem.numConstraint; i++) { | |||
1042 | tempIntegerArray[i] = mystranInstance->feaProblem.feaConstraint[i].constraintID; | |||
1043 | } | |||
1044 | ||||
1045 | // Write combined constraint card | |||
1046 | status = nastran_writeConstraintADDCard(fp, | |||
1047 | mystranInstance->feaProblem.numConstraint+1, | |||
1048 | mystranInstance->feaProblem.numConstraint, | |||
1049 | tempIntegerArray, | |||
1050 | &mystranInstance->feaProblem.feaFileFormat); | |||
1051 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1051, __func__, 0); goto cleanup; }; | |||
1052 | ||||
1053 | // Free temporary constraint ID list | |||
1054 | if (tempIntegerArray != NULL((void*)0)) EG_free(tempIntegerArray); | |||
1055 | tempIntegerArray = NULL((void*)0); | |||
1056 | } | |||
1057 | ||||
1058 | // Loads | |||
1059 | for (i = 0; i < mystranInstance->feaProblem.numLoad; i++) { | |||
1060 | status = nastran_writeLoadCard(fp, | |||
1061 | &feaLoad[i], | |||
1062 | &mystranInstance->feaProblem.feaFileFormat); | |||
1063 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1063, __func__, 0); goto cleanup; }; | |||
1064 | } | |||
1065 | ||||
1066 | // Constraints | |||
1067 | for (i = 0; i < mystranInstance->feaProblem.numConstraint; i++) { | |||
1068 | status = nastran_writeConstraintCard(fp, | |||
1069 | &mystranInstance->feaProblem.feaConstraint[i], | |||
1070 | &mystranInstance->feaProblem.feaFileFormat); | |||
1071 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1071, __func__, 0); goto cleanup; }; | |||
1072 | } | |||
1073 | ||||
1074 | // Supports | |||
1075 | for (i = 0; i < mystranInstance->feaProblem.numSupport; i++) { | |||
1076 | /*@-nullpass@*/ | |||
1077 | status = nastran_writeSupportCard(fp, | |||
1078 | &mystranInstance->feaProblem.feaSupport[i], | |||
1079 | &mystranInstance->feaProblem.feaFileFormat, | |||
1080 | NULL((void*)0)); | |||
1081 | /*@+nullpass@*/ | |||
1082 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1082, __func__, 0); goto cleanup; }; | |||
1083 | } | |||
1084 | ||||
1085 | // Materials | |||
1086 | for (i = 0; i < mystranInstance->feaProblem.numMaterial; i++) { | |||
1087 | status = nastran_writeMaterialCard(fp, | |||
1088 | &mystranInstance->feaProblem.feaMaterial[i], | |||
1089 | &mystranInstance->feaProblem.feaFileFormat); | |||
1090 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1090, __func__, 0); goto cleanup; }; | |||
1091 | } | |||
1092 | ||||
1093 | // Properties | |||
1094 | for (i = 0; i < mystranInstance->feaProblem.numProperty; i++) { | |||
1095 | status = nastran_writePropertyCard(fp, | |||
1096 | &mystranInstance->feaProblem.feaProperty[i], | |||
1097 | &mystranInstance->feaProblem.feaFileFormat); | |||
1098 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1098, __func__, 0); goto cleanup; }; | |||
1099 | } | |||
1100 | ||||
1101 | // Coordinate systems | |||
1102 | for (i = 0; i < mystranInstance->feaProblem.numCoordSystem; i++) { | |||
1103 | status = nastran_writeCoordinateSystemCard(fp, | |||
1104 | &mystranInstance->feaProblem.feaCoordSystem[i], | |||
1105 | &mystranInstance->feaProblem.feaFileFormat); | |||
1106 | AIM_STATUS(aimInfo, status)if (status != 0) { aim_status(aimInfo, status, "mystranAIM.c" , 1106, __func__, 0); goto cleanup; }; | |||
1107 | } | |||
1108 | ||||
1109 | // Include mesh file | |||
1110 | fprintf(fp,"INCLUDE \'%s.bdf\'\n", mystranInstance->projectName); | |||
1111 | ||||
1112 | // End bulk data | |||
1113 | fprintf(fp,"ENDDATA\n"); | |||
1114 | ||||
1115 | status = CAPS_SUCCESS0; | |||
1116 | ||||
1117 | cleanup: | |||
1118 | ||||
1119 | for (i = 0; i < mystranInstance->feaProblem.numLoad; i++) { | |||
1120 | destroy_feaLoadStruct(&feaLoad[i]); | |||
1121 | } | |||
1122 | AIM_FREE(feaLoad){ EG_free(feaLoad); feaLoad = ((void*)0); }; | |||
1123 | ||||
1124 | if (fp != NULL((void*)0)) fclose(fp); | |||
1125 | ||||
1126 | AIM_FREE(tempIntegerArray){ EG_free(tempIntegerArray); tempIntegerArray = ((void*)0); }; | |||
1127 | ||||
1128 | return status; | |||
1129 | } | |||
1130 | ||||
1131 | ||||
1132 | // ********************** AIM Function Break ***************************** | |||
1133 | int aimExecute(/*@unused@*/ const void *instStore, /*@unused@*/ void *aimInfo, | |||
1134 | int *state) | |||
1135 | { | |||
1136 | /*! \page aimExecuteMYSTRAN AIM Execution | |||
1137 | * | |||
1138 | * If auto execution is enabled when creating an MYSTRAN AIM, | |||
1139 | * the AIM will execute MYSTRAN just-in-time with the command line: | |||
1140 | * | |||
1141 | * \code{.sh} | |||
1142 | * mystran $Proj_Name.dat > Info.out | |||
1143 | * \endcode | |||
1144 | * | |||
1145 | * where preAnalysis generated the file Proj_Name + ".dat" which contains the input information. | |||
1146 | * | |||
1147 | * The analysis can be also be explicitly executed with caps_execute in the C-API | |||
1148 | * or via Analysis.runAnalysis in the pyCAPS API. | |||
1149 | * | |||
1150 | * Calling preAnalysis and postAnalysis is NOT allowed when auto execution is enabled. | |||
1151 | * | |||
1152 | * Auto execution can also be disabled when creating an MYSTRAN AIM object. | |||
1153 | * In this mode, caps_execute and Analysis.runAnalysis can be used to run the analysis, | |||
1154 | * or MYSTRAN can be executed by calling preAnalysis, system call, and posAnalysis as demonstrated | |||
1155 | * below with a pyCAPS example: | |||
1156 | * | |||
1157 | * \code{.py} | |||
1158 | * print ("\n\preAnalysis......") | |||
1159 | * mystran.preAnalysis() | |||
1160 | * | |||
1161 | * print ("\n\nRunning......") | |||
1162 | * mystran.system("mystran " + mystran.input.Proj_Name + ".dat > Info.out"); # Run via system call | |||
1163 | * | |||
1164 | * print ("\n\postAnalysis......") | |||
1165 | * mystran.postAnalysis() | |||
1166 | * \endcode | |||
1167 | */ | |||
1168 | ||||
1169 | char command[PATH_MAX4096]; | |||
1170 | const aimStorage *mystranInstance; | |||
1171 | *state = 0; | |||
1172 | ||||
1173 | mystranInstance = (const aimStorage *) instStore; | |||
1174 | if (mystranInstance == NULL((void*)0)) return CAPS_NULLVALUE-307; | |||
1175 | ||||
1176 | snprintf(command, PATH_MAX4096, "mystran %s.dat > Info.out", | |||
1177 | mystranInstance->projectName); | |||
1178 | ||||
1179 | return aim_system(aimInfo, NULL((void*)0), command); | |||
1180 | } | |||
1181 | ||||
1182 | ||||
1183 | // ********************** AIM Function Break ***************************** | |||
1184 | // Check that MYSTRAN ran without errors | |||
1185 | int aimPostAnalysis(void *instStore, /*@unused@*/ void *aimInfo, | |||
1186 | /*@unused@*/ int restart, /*@unused@*/ capsValue *inputs) | |||
1187 | { | |||
1188 | int status; | |||
1189 | char *filename = NULL((void*)0); // File to open | |||
1190 | char extF06[] = ".F06"; | |||
1191 | FILE *fp = NULL((void*)0); // File pointer | |||
1192 | aimStorage *mystranInstance; | |||
1193 | ||||
1194 | #ifdef DEBUG | |||
1195 | printf(" astrosAIM/aimPostAnalysis!\n"); | |||
1196 | #endif | |||
1197 | mystranInstance = (aimStorage *) instStore; | |||
1198 | ||||
1199 | // check that the mystran *.F06 file was created | |||
1200 | filename = (char *) EG_alloc((strlen(mystranInstance->projectName) + | |||
1201 | strlen(extF06)+1)*sizeof(char)); | |||
1202 | if (filename == NULL((void*)0)) return EGADS_MALLOC-4; | |||
1203 | ||||
1204 | sprintf(filename, "%s%s", mystranInstance->projectName, extF06); | |||
1205 | ||||
1206 | fp = aim_fopen(aimInfo, filename, "r"); | |||
1207 | if (fp == NULL((void*)0)) { | |||
1208 | AIM_ERROR(aimInfo, "Cannot open Output file: %s!", filename){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 1208, __func__ , "Cannot open Output file: %s!", filename); }; | |||
1209 | status = CAPS_IOERR-332; | |||
1210 | goto cleanup; | |||
1211 | } | |||
1212 | status = CAPS_SUCCESS0; | |||
1213 | ||||
1214 | cleanup: | |||
1215 | EG_free(filename); // Free filename allocation | |||
1216 | if (fp != NULL((void*)0)) fclose(fp); | |||
1217 | ||||
1218 | return status; | |||
1219 | } | |||
1220 | ||||
1221 | ||||
1222 | // Set MYSTRAN output variables | |||
1223 | int aimOutputs(/*@unused@*/ void *instStore, /*@unused@*/ void *aimStruc, | |||
1224 | int index, char **aoname, capsValue *form) | |||
1225 | { | |||
1226 | /*! \page aimOutputsMYSTRAN AIM Outputs | |||
1227 | * The following list outlines the MYSTRAN outputs available through the AIM interface. | |||
1228 | */ | |||
1229 | ||||
1230 | #ifdef DEBUG | |||
1231 | printf(" mystranAIM/aimOutputs index = %d!\n", index); | |||
1232 | #endif | |||
1233 | ||||
1234 | /*! \page aimOutputsMYSTRAN AIM Outputs | |||
1235 | * - <B>EigenValue</B> = List of Eigen-Values (\f$ \lambda\f$) after a modal solve. | |||
1236 | * - <B>EigenRadian</B> = List of Eigen-Values in terms of radians (\f$ \omega = \sqrt{\lambda}\f$ ) after a modal solve. | |||
1237 | * - <B>EigenFrequency</B> = List of Eigen-Values in terms of frequencies (\f$ f = \frac{\omega}{2\pi}\f$) after a modal solve. | |||
1238 | * - <B>EigenGeneralMass</B> = List of generalized masses for the Eigen-Values. | |||
1239 | * . | |||
1240 | */ | |||
1241 | ||||
1242 | if (index == 1) { | |||
1243 | *aoname = EG_strdup("EigenValue"); | |||
1244 | ||||
1245 | } else if (index == 2) { | |||
1246 | *aoname = EG_strdup("EigenRadian"); | |||
1247 | ||||
1248 | } else if (index == 3) { | |||
1249 | *aoname = EG_strdup("EigenFrequency"); | |||
1250 | ||||
1251 | } else if (index == 4) { | |||
1252 | *aoname = EG_strdup("EigenGeneralMass"); | |||
1253 | } | |||
1254 | ||||
1255 | form->type = Double; | |||
1256 | form->units = NULL((void*)0); | |||
1257 | form->lfixed = Change; | |||
1258 | form->sfixed = Change; | |||
1259 | form->vals.reals = NULL((void*)0); | |||
1260 | form->vals.real = 0; | |||
1261 | ||||
1262 | /*else if (index == 3) { | |||
1263 | *aoname = EG_strdup("EigenVector"); | |||
1264 | form->type = Double; | |||
1265 | form->units = NULL; | |||
1266 | form->lfixed = Change; | |||
1267 | form->sfixed = Change; | |||
1268 | }*/ | |||
1269 | ||||
1270 | return CAPS_SUCCESS0; | |||
1271 | } | |||
1272 | ||||
1273 | ||||
1274 | // Calculate MYSTRAN output | |||
1275 | int aimCalcOutput(void *instStore, /*@unused@*/ void *aimInfo, int index, | |||
1276 | capsValue *val) | |||
1277 | { | |||
1278 | int status = CAPS_SUCCESS0; // Function return status | |||
1279 | ||||
1280 | int i; // Indexing | |||
1281 | ||||
1282 | char filename[PATH_MAX4096]; // File to open | |||
1283 | char extOU1[] = ".OU1"; | |||
1284 | char extF06[] = ".F06"; | |||
1285 | FILE *fp = NULL((void*)0); // File pointer | |||
1286 | aimStorage *mystranInstance; | |||
1287 | ||||
1288 | const double pi = 4.0 * atan(1.0); | |||
1289 | ||||
1290 | mystranInstance = (aimStorage *) instStore; | |||
1291 | ||||
1292 | if (index == 1 || index == 2 || index == 3) { | |||
1293 | // Open mystran *.OU1 file - OUTPUT4 | |||
1294 | snprintf(filename, PATH_MAX4096, "%s%s", mystranInstance->projectName, extOU1); | |||
1295 | ||||
1296 | fp = aim_fopen(aimInfo, filename, "rb"); | |||
1297 | if (fp == NULL((void*)0)) { | |||
1298 | #ifdef DEBUG | |||
1299 | printf(" mystranAIM/aimCalcOutput Cannot open Output file!\n"); | |||
1300 | #endif | |||
1301 | AIM_ERROR(aimInfo, "Failed to open %s", filename){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 1301, __func__ , "Failed to open %s", filename); }; | |||
1302 | return CAPS_IOERR-332; | |||
1303 | } | |||
1304 | ||||
1305 | status = mystran_readOutput4Data(fp, "EIGEN_VA", val); | |||
1306 | if (status == CAPS_SUCCESS0) { | |||
1307 | if (index == 2) { | |||
1308 | for (i = 0; i < val->length; i++) { | |||
1309 | val->vals.reals[i] = sqrt(val->vals.reals[i]); | |||
1310 | } | |||
1311 | //val->units = EG_strdup("rads/s"); | |||
1312 | } | |||
1313 | ||||
1314 | if (index == 3) { | |||
1315 | for (i = 0; i < val->length; i++) { | |||
1316 | val->vals.reals[i] = sqrt(val->vals.reals[i])/(2*pi); | |||
1317 | } | |||
1318 | //val->units = EG_strdup("Hz"); | |||
1319 | } | |||
1320 | } | |||
1321 | ||||
1322 | } else if (index == 4) { | |||
1323 | // Open mystran *.OU1 file - OUTPUT4 | |||
1324 | snprintf(filename, PATH_MAX4096, "%s%s", mystranInstance->projectName, extOU1); | |||
1325 | ||||
1326 | fp = aim_fopen(aimInfo, filename, "rb"); | |||
1327 | ||||
1328 | if (fp == NULL((void*)0)) { | |||
1329 | #ifdef DEBUG | |||
1330 | printf(" mystranAIM/aimCalcOutput Cannot open Output file!\n"); | |||
1331 | #endif | |||
1332 | AIM_ERROR(aimInfo, "Failed to open %s", filename){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 1332, __func__ , "Failed to open %s", filename); }; | |||
1333 | return CAPS_IOERR-332; | |||
1334 | } | |||
1335 | ||||
1336 | status = mystran_readOutput4Data(fp, "GEN_MASS", val); | |||
1337 | ||||
1338 | } else if (index == 5) { | |||
1339 | ||||
1340 | // Open mystran *.F06 file | |||
1341 | snprintf(filename, PATH_MAX4096, "%s%s", mystranInstance->projectName, extF06); | |||
1342 | ||||
1343 | fp = aim_fopen(aimInfo, filename, "r"); | |||
1344 | ||||
1345 | if (fp == NULL((void*)0)) { | |||
1346 | #ifdef DEBUG | |||
1347 | printf(" mystranAIM/aimCalcOutput Cannot open Output file!\n"); | |||
1348 | #endif | |||
1349 | AIM_ERROR(aimInfo, "Failed to open %s", filename){ aim_message(aimInfo, CERROR, 0 , "mystranAIM.c", 1349, __func__ , "Failed to open %s", filename); }; | |||
1350 | return CAPS_IOERR-332; | |||
1351 | } | |||
1352 | /* | |||
1353 | double **dataMatrix = NULL; | |||
1354 | int numEigenVector = 0; | |||
1355 | int numGridPoint = 0; | |||
1356 | status = mystran_readF06Eigen(fp, &numEigenVector, &numGridPoint, | |||
1357 | &dataMatrix); | |||
1358 | */ | |||
1359 | } | |||
1360 | ||||
1361 | if (fp != NULL((void*)0)) fclose(fp); | |||
1362 | ||||
1363 | return status; | |||
1364 | } | |||
1365 | ||||
1366 | ||||
1367 | void aimCleanup(void *instStore) | |||
1368 | { | |||
1369 | int status; // Returning status | |||
1370 | aimStorage *mystranInstance; | |||
1371 | ||||
1372 | #ifdef DEBUG | |||
1373 | printf(" mystranAIM/aimCleanup!\n"); | |||
1374 | #endif | |||
1375 | mystranInstance = (aimStorage *) instStore; | |||
1376 | ||||
1377 | status = destroy_aimStorage(mystranInstance); | |||
1378 | if (status != CAPS_SUCCESS0) | |||
1379 | printf("Error: Status %d during clean up of instance\n", status); | |||
1380 | ||||
1381 | EG_free(mystranInstance); | |||
1382 | } | |||
1383 | ||||
1384 | ||||
1385 | int aimDiscr(char *tname, capsDiscr *discr) | |||
1386 | { | |||
1387 | int status; // Function return status | |||
1388 | ||||
1389 | aimStorage *mystranInstance; | |||
1390 | ||||
1391 | int i, numBody; | |||
1392 | ||||
1393 | // EGADS objects | |||
1394 | ego *bodies = NULL((void*)0), *tess = NULL((void*)0); | |||
1395 | ||||
1396 | const char *intents; | |||
1397 | ||||
1398 | #ifdef DEBUG | |||
1399 | printf(" mystranAIM/aimDiscr: tname = %s!\n", tname); | |||
1400 | #endif | |||
1401 | ||||
1402 | if (tname == NULL((void*)0)) return CAPS_NOTFOUND-303; | |||
1403 | mystranInstance = (aimStorage *) discr->instStore; | |||
1404 | ||||
1405 | /* if (mystranInstance->dataTransferCheck == (int) false) { | |||
1406 | printf("The volume is not suitable for data transfer - possibly the volume mesher " | |||
1407 | "added unaccounted for points\n"); | |||
1408 | return CAPS_BADVALUE; | |||
1409 | }*/ | |||
1410 | ||||
1411 | // Currently this ONLY works if the capsTranfer lives on single body! | |||
1412 | status = aim_getBodies(discr->aInfo, &intents, &numBody, &bodies); | |||
1413 | if ((status != CAPS_SUCCESS0) || (bodies == NULL((void*)0))) { | |||
1414 | if (status == CAPS_SUCCESS0) status = CAPS_NULLOBJ-309; | |||
1415 | printf(" mystranAIM/aimDiscr: aim_getBodies = %d!\n", status); | |||
1416 | return status; | |||
1417 | } | |||
1418 | ||||
1419 | // Check and generate/retrieve the mesh | |||
1420 | status = checkAndCreateMesh(discr->aInfo, mystranInstance); | |||
1421 | AIM_STATUS(discr->aInfo, status)if (status != 0) { aim_status(discr->aInfo, status, "mystranAIM.c" , 1421, __func__, 0); goto cleanup; }; | |||
1422 | ||||
1423 | AIM_ALLOC(tess, mystranInstance->numMesh, ego, discr->aInfo, status){ if (tess != ((void*)0)) { status = -4; aim_status(discr-> aInfo, status, "mystranAIM.c", 1423, __func__, 1, "AIM_ALLOC: %s != NULL" , "tess"); goto cleanup; } size_t memorysize = mystranInstance ->numMesh; tess = (ego *) EG_alloc(memorysize*sizeof(ego)) ; if (tess == ((void*)0)) { status = -4; aim_status(discr-> aInfo, status, "mystranAIM.c", 1423, __func__, 3, "AIM_ALLOC: %s size %zu type %s" , "tess", memorysize, "ego"); goto cleanup; } }; | |||
1424 | for (i = 0; i < mystranInstance->numMesh; i++) { | |||
1425 | tess[i] = mystranInstance->feaMesh[i].egadsTess; | |||
1426 | } | |||
1427 | ||||
1428 | status = mesh_fillDiscr(tname, &mystranInstance->attrMap, mystranInstance->numMesh, tess, discr); | |||
1429 | AIM_STATUS(discr->aInfo, status)if (status != 0) { aim_status(discr->aInfo, status, "mystranAIM.c" , 1429, __func__, 0); goto cleanup; }; | |||
1430 | ||||
1431 | #ifdef DEBUG | |||
1432 | printf(" mystranAIM/aimDiscr: Instance = %d, Finished!!\n", iIndex); | |||
1433 | #endif | |||
1434 | ||||
1435 | status = CAPS_SUCCESS0; | |||
1436 | ||||
1437 | cleanup: | |||
1438 | if (status != CAPS_SUCCESS0) | |||
1439 | printf("\tPremature exit: function aimDiscr mystranAIM status = %d\n", | |||
1440 | status); | |||
1441 | ||||
1442 | AIM_FREE(tess){ EG_free(tess); tess = ((void*)0); }; | |||
1443 | return status; | |||
1444 | } | |||
1445 | ||||
1446 | ||||
1447 | int aimTransfer(capsDiscr *discr, const char *dataName, int numPoint, | |||
1448 | int dataRank, double *dataVal, /*@unused@*/ char **units) | |||
1449 | { | |||
1450 | ||||
1451 | /*! \page dataTransferMYSTRAN MYSTRAN Data Transfer | |||
1452 | * | |||
1453 | * The MYSTRAN AIM has the ability to transfer displacements and eigenvectors from the AIM and pressure | |||
1454 | * distributions to the AIM using the conservative and interpolative data transfer schemes in CAPS. | |||
1455 | * | |||
1456 | * \section dataFromMYSTRAN Data transfer from MYSTRAN (FieldOut) | |||
1457 | * | |||
1458 | * <ul> | |||
1459 | * <li> <B>"Displacement"</B> </li> <br> | |||
1460 | * Retrieves nodal displacements from the *.F06 file. | |||
1461 | * </ul> | |||
1462 | * | |||
1463 | * <ul> | |||
1464 | * <li> <B>"EigenVector_#"</B> </li> <br> | |||
1465 | * Retrieves modal eigen-vectors from the *.F06 file, where "#" should be replaced by the | |||
1466 | * corresponding mode number for the eigen-vector (eg. EigenVector_3 would correspond to the third mode, | |||
1467 | * while EigenVector_6 would be the sixth mode). | |||
1468 | * </ul> | |||
1469 | * | |||
1470 | * \section dataToMYSTRAN Data transfer to MYSTRAN (FieldIn) | |||
1471 | * <ul> | |||
1472 | * <li> <B>"Pressure"</B> </li> <br> | |||
1473 | * Writes appropriate load cards using the provided pressure distribution. | |||
1474 | * </ul> | |||
1475 | * | |||
1476 | */ | |||
1477 | ||||
1478 | int status; // Function return status | |||
1479 | int i, j, dataPoint, bIndex; // Indexing | |||
1480 | aimStorage *mystranInstance; | |||
1481 | ||||
1482 | char *extF06 = ".F06"; | |||
1483 | ||||
1484 | // FO6 data variables | |||
1485 | int numGridPoint = 0; | |||
1486 | int numEigenVector = 0; | |||
1487 | ||||
1488 | double **dataMatrix = NULL((void*)0); | |||
1489 | ||||
1490 | // Specific EigenVector to use | |||
1491 | int eigenVectorIndex = 0; | |||
1492 | ||||
1493 | // Variables used in global node mapping | |||
1494 | int globalNodeID; | |||
1495 | ||||
1496 | // Filename stuff | |||
1497 | char *filename = NULL((void*)0); | |||
1498 | FILE *fp; // File pointer | |||
1499 | ||||
1500 | #ifdef DEBUG | |||
1501 | printf(" mystranAIM/aimTransfer name = %s npts = %d/%d!\n", | |||
1502 | dataName, numPoint, dataRank); | |||
1503 | #endif | |||
1504 | mystranInstance = (aimStorage *) discr->instStore; | |||
1505 | ||||
1506 | //capsGroupList = &storage[0]; // List of boundary ID (attrMap) in the transfer | |||
1507 | ||||
1508 | if (strcasecmp(dataName, "Displacement") != 0 && | |||
1509 | strncmp(dataName, "EigenVector", 11) != 0) { | |||
1510 | ||||
1511 | printf("Unrecognized data transfer variable - %s\n", dataName); | |||
1512 | return CAPS_NOTFOUND-303; | |||
1513 | } | |||
1514 | ||||
1515 | filename = (char *) EG_alloc((strlen(mystranInstance->projectName) + | |||
1516 | strlen(extF06) + 1)*sizeof(char)); | |||
1517 | if (filename == NULL((void*)0)) return EGADS_MALLOC-4; | |||
1518 | ||||
1519 | sprintf(filename,"%s%s", mystranInstance->projectName, extF06); | |||
1520 | ||||
1521 | // Open file | |||
1522 | fp = aim_fopen(discr->aInfo, filename, "r"); | |||
1523 | if (fp == NULL((void*)0)) { | |||
1524 | printf("Unable to open file: %s\n", filename); | |||
1525 | if (filename != NULL((void*)0)) EG_free(filename); | |||
1526 | return CAPS_IOERR-332; | |||
1527 | } | |||
1528 | ||||
1529 | if (filename != NULL((void*)0)) EG_free(filename); | |||
1530 | filename = NULL((void*)0); | |||
1531 | ||||
1532 | if (strcasecmp(dataName, "Displacement") == 0) { | |||
1533 | ||||
1534 | if (dataRank != 3) { | |||
1535 | ||||
1536 | printf("Invalid rank for dataName \"%s\" - excepted a rank of 3!!!\n", | |||
1537 | dataName); | |||
1538 | status = CAPS_BADRANK-301; | |||
1539 | ||||
1540 | } else { | |||
1541 | ||||
1542 | status = mystran_readF06Displacement(fp, | |||
1543 | 1, | |||
1544 | &numGridPoint, | |||
1545 | &dataMatrix); | |||
1546 | fclose(fp); | |||
1547 | } | |||
1548 | ||||
1549 | } else if (strncmp(dataName, "EigenVector", 11) == 0) { | |||
1550 | ||||
1551 | // Which EigenVector do we want ? | |||
1552 | for (i = 0; i < strlen(dataName); i++) { | |||
1553 | if (dataName[i] == '_' ) break; | |||
1554 | } | |||
1555 | ||||
1556 | if (i == strlen(dataName)) { | |||
1557 | eigenVectorIndex = 1; | |||
1558 | } else { | |||
1559 | ||||
1560 | status = sscanf(dataName, "EigenVector_%d", &eigenVectorIndex); | |||
1561 | if (status != 1) { | |||
1562 | printf("Unable to determine which EigenVector to use - Defaulting the first EigenVector!!!\n"); | |||
1563 | eigenVectorIndex = 1; | |||
1564 | } | |||
1565 | } | |||
1566 | ||||
1567 | if (dataRank != 3) { | |||
1568 | ||||
1569 | printf("Invalid rank for dataName \"%s\" - excepted a rank of 3!!!\n", | |||
1570 | dataName); | |||
1571 | status = CAPS_BADRANK-301; | |||
1572 | ||||
1573 | } else { | |||
1574 | ||||
1575 | status = mystran_readF06EigenVector(fp, | |||
1576 | &numEigenVector, | |||
1577 | &numGridPoint, | |||
1578 | &dataMatrix); | |||
1579 | } | |||
1580 | ||||
1581 | fclose(fp); | |||
1582 | ||||
1583 | } else { | |||
1584 | ||||
1585 | status = CAPS_NOTFOUND-303; | |||
1586 | } | |||
1587 | ||||
1588 | if (status != CAPS_SUCCESS0) return status; | |||
1589 | ||||
1590 | // Check EigenVector range | |||
1591 | if (strncmp(dataName, "EigenVector", 11) == 0) { | |||
1592 | if (eigenVectorIndex > numEigenVector) { | |||
1593 | printf("Only %d EigenVectors found but index %d requested!\n", | |||
1594 | numEigenVector, eigenVectorIndex); | |||
1595 | status = CAPS_RANGEERR-326; | |||
1596 | goto cleanup; | |||
1597 | } | |||
1598 | ||||
1599 | if (eigenVectorIndex < 1) { | |||
1600 | printf("For EigenVector_X notation, X must be >= 1, currently X = %d\n", | |||
1601 | eigenVectorIndex); | |||
1602 | status = CAPS_RANGEERR-326; | |||
1603 | goto cleanup; | |||
1604 | } | |||
1605 | } | |||
1606 | if (dataMatrix == NULL((void*)0)) { | |||
1607 | status = CAPS_NULLVALUE-307; | |||
1608 | goto cleanup; | |||
1609 | } | |||
1610 | ||||
1611 | for (i = 0; i < numPoint; i++) { | |||
1612 | ||||
1613 | bIndex = discr->tessGlobal[2*i ]; | |||
1614 | globalNodeID = discr->tessGlobal[2*i+1] + | |||
1615 | discr->bodys[bIndex-1].globalOffset; | |||
1616 | ||||
1617 | if (strcasecmp(dataName, "Displacement") == 0) { | |||
1618 | ||||
1619 | for (dataPoint = 0; dataPoint < numGridPoint; dataPoint++) { | |||
1620 | if ((int) dataMatrix[dataPoint][0] == globalNodeID) break; | |||
1621 | } | |||
1622 | ||||
1623 | if (dataPoint == numGridPoint) { | |||
1624 | printf("Unable to locate global ID = %d in the data matrix\n", | |||
1625 | globalNodeID); | |||
1626 | status = CAPS_NOTFOUND-303; | |||
1627 | goto cleanup; | |||
1628 | } | |||
1629 | ||||
1630 | dataVal[dataRank*i+0] = dataMatrix[dataPoint][2]; // T1 | |||
1631 | dataVal[dataRank*i+1] = dataMatrix[dataPoint][3]; // T2 | |||
1632 | dataVal[dataRank*i+2] = dataMatrix[dataPoint][4]; // T3 | |||
1633 | ||||
1634 | } else if (strncmp(dataName, "EigenVector", 11) == 0) { | |||
1635 | ||||
1636 | for (dataPoint = 0; dataPoint < numGridPoint; dataPoint++) { | |||
1637 | if ((int) dataMatrix[eigenVectorIndex - 1][8*dataPoint + 0] == | |||
1638 | globalNodeID) break; | |||
1639 | } | |||
1640 | ||||
1641 | if (dataPoint == numGridPoint) { | |||
1642 | printf("Unable to locate global ID = %d in the data matrix\n", | |||
1643 | globalNodeID); | |||
1644 | status = CAPS_NOTFOUND-303; | |||
1645 | goto cleanup; | |||
1646 | } | |||
1647 | ||||
1648 | dataVal[dataRank*i+0] = dataMatrix[eigenVectorIndex- 1][8*dataPoint + 2]; // T1 | |||
1649 | dataVal[dataRank*i+1] = dataMatrix[eigenVectorIndex- 1][8*dataPoint + 3]; // T2 | |||
1650 | dataVal[dataRank*i+2] = dataMatrix[eigenVectorIndex- 1][8*dataPoint + 4]; // T3 | |||
1651 | //dataVal[dataRank*i+3] = dataMatrix[eigenVectorIndex- 1][8*dataPoint + 5]; // R1 - Don't use rotations | |||
1652 | //dataVal[dataRank*i+4] = dataMatrix[eigenVectorIndex- 1][8*dataPoint + 6]; // R2 | |||
1653 | //dataVal[dataRank*i+5] = dataMatrix[eigenVectorIndex- 1][8*dataPoint + 7]; // R3 | |||
1654 | ||||
1655 | } | |||
1656 | } | |||
1657 | ||||
1658 | status = CAPS_SUCCESS0; | |||
1659 | ||||
1660 | cleanup: | |||
1661 | // Free data matrix | |||
1662 | if (dataMatrix != NULL((void*)0)) { | |||
1663 | j = 0; | |||
1664 | if (strcasecmp(dataName, "Displacement") == 0) j = numGridPoint; | |||
1665 | else if (strncmp(dataName, "EigenVector", 11) == 0) j = numEigenVector; | |||
1666 | ||||
1667 | for (i = 0; i < j; i++) { | |||
1668 | if (dataMatrix[i] != NULL((void*)0)) EG_free(dataMatrix[i]); | |||
1669 | } | |||
1670 | EG_free(dataMatrix); | |||
1671 | } | |||
1672 | ||||
1673 | return status; | |||
1674 | } | |||
1675 | ||||
1676 | ||||
1677 | void aimFreeDiscrPtr(void *ptr) | |||
1678 | { | |||
1679 | EG_free(ptr); // Extra information to store into the discr void pointer - just a int array | |||
1680 | } | |||
1681 | ||||
1682 | ||||
1683 | int aimLocateElement(capsDiscr *discr, double *params, double *param, | |||
1684 | int *bIndex, int *eIndex, double *bary) | |||
1685 | { | |||
1686 | #ifdef DEBUG | |||
1687 | printf(" mystranAIM/aimLocateElement!\n"); | |||
1688 | #endif | |||
1689 | ||||
1690 | return aim_locateElement(discr, params, param, bIndex, eIndex, bary); | |||
1691 | } | |||
1692 | ||||
1693 | ||||
1694 | int aimInterpolation(capsDiscr *discr, const char *name, int bIndex, int eIndex, | |||
1695 | double *bary, int rank, double *data, double *result) | |||
1696 | { | |||
1697 | #ifdef DEBUG | |||
1698 | printf(" mystranAIM/aimInterpolation %s!\n", name); | |||
1699 | #endif | |||
1700 | ||||
1701 | return aim_interpolation(discr, name, bIndex, eIndex, bary, rank, data, | |||
1702 | result); | |||
1703 | ||||
1704 | } | |||
1705 | ||||
1706 | ||||
1707 | int aimInterpolateBar(capsDiscr *discr, const char *name, int bIndex, | |||
1708 | int eIndex, double *bary, int rank, | |||
1709 | double *r_bar, double *d_bar) | |||
1710 | { | |||
1711 | #ifdef DEBUG | |||
1712 | printf(" mystranAIM/aimInterpolateBar %s!\n", name); | |||
1713 | #endif | |||
1714 | ||||
1715 | return aim_interpolateBar(discr, name, bIndex, eIndex, bary, rank, r_bar, | |||
1716 | d_bar); | |||
1717 | } | |||
1718 | ||||
1719 | ||||
1720 | int aimIntegration(capsDiscr *discr, const char *name, int bIndex, int eIndex, | |||
1721 | int rank, double *data, double *result) | |||
1722 | { | |||
1723 | #ifdef DEBUG | |||
1724 | printf(" mystranAIM/aimIntegration %s!\n", name); | |||
1725 | #endif | |||
1726 | ||||
1727 | return aim_integration(discr, name, bIndex, eIndex, rank, data, result); | |||
1728 | } | |||
1729 | ||||
1730 | ||||
1731 | int aimIntegrateBar(capsDiscr *discr, const char *name, int bIndex, int eIndex, | |||
1732 | int rank, double *r_bar, double *d_bar) | |||
1733 | { | |||
1734 | #ifdef DEBUG | |||
1735 | printf(" mystranAIM/aimIntegrateBar %s!\n", name); | |||
1736 | #endif | |||
1737 | ||||
1738 | return aim_integrateBar(discr, name, bIndex, eIndex, rank, r_bar, d_bar); | |||
1739 | } |