Skip to content

Changes

#178 (Apr 8, 2023, 9:13:11 AM)

  1. Fix aflr2 for Phasing — galbramc / detail
  2. Fix compile warning — galbramc / detail
  3. Fix for AFLR2 — galbramc / detail
  4. Comment out debug code — galbramc / detail
  5. Allow AFLR2 to work with multiple faces — galbramc / detail
  6. Only build Writer directories on Windoze — galbramc / detail
  7. Add meshWriter NMakefile verbosity — galbramc / detail
  8. Suppress lint warning — galbramc / detail
  9. NMakefile fix — galbramc / detail
  10. Fix NMakefiles for meshWriter — galbramc / detail
  11. Documentation updates — galbramc / detail
  12. Upgrade fun3d cython files — galbramc / detail
  13. One more try at AIM_NOTFOUND — galbramc / detail
  14. Add AIM_NOTFOUND macro — galbramc / detail
  15. Add aimInfo to fea_getDesignResponse — galbramc / detail
  16. Test cart3d on commit again — galbramc / detail
  17. Remove Cart3D from commit testing for now — galbramc / detail
  18. Dissable tecplot debug dump for aflr4 — galbramc / detail
  19. Fix compiler warning — galbramc / detail
  20. add code to protect for UDFs that have references to its input Model; add (hidden) option to create timingReport.txt file; improve flends; add flend9* test cases — jfdannen / detail
  21. update flend8* test cases and their verification data — jfdannen / detail
  22. fix lint error in udfMatchBodys; re-add 7.4.1 verification data for flend8* test cases — jfdannen / detail
  23. change flend fits to be better in some cases; track down memory leaks — jfdannen / detail
  24. fix problem erroneously flagged by lint in udpOffset; update errors reported by udfFlend; fix bug where wrong UDP storage was used in udfOffset (which caused problems when udpOffset was called more than once); remove SPECIAL test of EG_otherCurve; document .multiNode use in RULE command; fix bug where UDP storage is incorrectly cleared for an embedded UDP (in udpCsm); fix bug in udfFlend that sometimes did not correctly reverse one of the Loops; fix memory leak in EVALUATE EDGEKT, EDGECP, FACEUKT, FACEVKT, and FACECP when a signal is raised — jfdannen / detail
  25. fix compiler warning in latest commit — jfdannen / detail
  26. account for fact that Py_SetPythonHome was deprecated in Python 3.11; update udfOffset so that it can generate offsets on SolidBodys (for FLENDs); add offset(I-R)* test cases; use zebra stripe coloring for maximum curvature in ESP (displayType=4); update convertToBsplines to reuse Pcurves whenever possible; add udpBspline and bspline* test cases — jfdannen / detail
  27. Fix getEdgeUV doc — galbramc / detail
  28. Fix full attirubtion for EG_repalceFaces. Fix error message. — galbramc / detail
  29. Remove depricated x86 -m64 compiler flag. Add compiler flags for OCC 7.7. — galbramc / detail
  30. update expected flend8* failures — jfdannen / detail
  31. Put file names first — galbramc / detail
  32. Add OCC 7.7 Jenkins data — galbramc / detail
  33. add expected errors selected in flend8* test cases — jfdannen / detail
  34. Cart3D env fix — galbramc / detail
  35. Upgrade Cart3D version — galbramc / detail
  36. Update for OCC 7.7.0 — galbramc / detail

#177 (Mar 11, 2023, 12:14:07 AM)

  1. Upgrade to AFLR 11.3.17 — galbramc / detail
  2. Updated makefiles for AFLR 11.3.17. Add doc about capsFile. — galbramc / detail
  3. Fix typo — galbramc / detail
  4. Allow aflr4 to mesh abutting bodies with matching faces. — galbramc / detail
  5. fix memory leak in Slugs; update Makefile.DARWIN64 in Slugs to have sanitize targets — jfdannen / detail
  6. Fix block name for exodusWriter. Add symbolic link to mesh for plato AIM. — galbramc / detail
  7. improve printing of Pcurves in ocsmPrintEgo; improve marking of Faces with _body and _brch Attributes when returned from a UDF; add PRINT_MAPPING_INFO define to OpenCSM; fix bug that did not account for Node and Edge sensitivities when report sensitivity range in serveESP; fix bug that occasionally did not properly compute Node tessellation sensitivities — jfdannen / detail
  8. add EVALUATE EDGEKT, EVALUATE EDGECP, EVALUATE FACEUKT, EVALUATE FACEVKT, and EVALUATE FACECP; add evaluate3* test cases; add multiRegions* test cases; add SELECT FLIP to flip the order of rntities in at-sellist — jfdannen / detail
  9. add copyAttr=0 argument to RULE and BLEND to copy Edge Attributes in xsects onto RULE/BLEND Edges; add blend29 and rule29 test cases — jfdannen / detail
  10. improve test for matching Nodes in udfMatchBodys; adjust matchBodys5 test case to check at-at-parameters — jfdannen / detail
  11. add arcLengths to ocsmPrintEgo; fix bug in udfMatchBodys when tol was large — jfdannen / detail
  12. modify udfMatchBodys to transfer an Attribute from one Body to the other when the Nodes, Edges, or Faces match; add matchBody5 test case — jfdannen / detail
  13. fix bug associated with UDP/UDF outputs that change shape — jfdannen / detail
  14. remove stanalyzer false positive by disabling checks for one loop in udfTester1.c — jfdannen / detail
  15. attempt to fix stanalizer error in udfTester1.c — jfdannen / detail
  16. allow at-at-parameters from a UDP/UDF to have velocities; split udpTest into udfTester1 (to demonstrate matrix outputs from a UDP/UDF) and udpTester2 (to demonstrate output velocities from a UDP/UDF); adjust Makefiles and associated test cases — jfdannen / detail
  17. Fix for OCC 7.4 — galbramc / detail
  18. Provide error message instead of segfault in EG_otherCurve — galbramc / detail
  19. Add 1-bias to matchBody documentation — galbramc / detail
  20. Upgrade to AFLR 11.3.17 — galbramc / detail

#176 (Feb 11, 2023, 11:03:17 AM)

  1. Try that one more time — galbramc / detail
  2. Use and empty mesh instead of edge only for aflr2 tessellation — galbramc / detail
  3. Fix warning — galbramc / detail
  4. Fix uninitialized data in AFLR3 — galbramc / detail
  5. Add meshRef mapping for aflr2 — galbramc / detail
  6. Updated AFLR4 files for new Quading — galbramc / detail
  7. Upgrade to AFLR 11.3.15 — galbramc / detail
  8. Fix for 2D meshing — galbramc / detail
  9. Forgot a file — galbramc / detail
  10. Another try at the stanalizer — galbramc / detail
  11. Fix stanalizer warning — galbramc / detail
  12. Restore CAPS training files — galbramc / detail
  13. Add support for exodux Nodeset. Add surface morphing for plato aim (no volume morphing). — galbramc / detail
  14. another attempt to eliminate spurious compiler warnings — jfdannen / detail
  15. another attempt to fix spurious warning messages — jfdannen / detail
  16. fix to avoid compiler warnings — jfdannen / detail
  17. numerous updates to Slugs — jfdannen / detail
  18. Fix uninitialized data — galbramc / detail
  19. Fix last commit — galbramc / detail
  20. Fix surface to volume map for aflr3 MultiDomain — galbramc / detail
  21. Plug two aflr3 leaks — galbramc / detail
  22. Fix bug introduced in AFLR4 — galbramc / detail
  23. Fix MultiDomain mapvol for aflr3 — galbramc / detail
  24. Warning and lint fixes — galbramc / detail
  25. Update AFLR3 to work for MultiDomain. Add eto dump for plato AIM. Update TACS dox. Add more plato examples. — galbramc / detail
  26. add test.so to Makefiles; add diagnostic printouts when a Face does not tessellate; make sure all UDP/UDFs return output values to the numUdp instance — jfdannen / detail
  27. allow number of rows and columns to be accessible in UDPs; allow at-at-parameters from a UDP/UDF to be vectors or matricies; add udp_error1 to udp_error9 as possible argument to CATBEG statement; fix bug that did not restore at-at-parameters when a UDP/UDF was recycled; refactor way UDP/UDF arguments are handled — jfdannen / detail
  28. update header files to allow use of C++ main program; add simpleCSM.cpp and modify Makefile.DARWIN64 for testing — jfdannen / detail
  29. change udfSlices to skip a slice if OpenCASCADE fails (rather than return an eror); add SET statement to udpWaffle;  add waffleB1 and waffleB2 test cases; fix bug in plotting of normals in serveESP and serveCSM; add PRINT_RULE_KNOTS to print number of knots in BSPLINEs entering a RULE or BLEND; allow -ATTRREALSENS to indicate a UDPRIM parameter that is intended to signal that Parameter is used within an included file; add waffleB3 test case to demonstrate this; add waffleB3.jrnl to demonstrate generation of .sens file for every DESPMTR without rebuilds — jfdannen / detail
  30. update return values from udpTire — jfdannen / detail
  31. Suppport Edge only eto files — galbramc / detail
  32. update DARWIN64.gcc to add comma to RPATH needed by some gcc-10 compilers — jfdannen / detail
  33. Add back ESP_ROOT/lib to rpath on DARWIN — galbramc / detail
  34. Use @loader_path for rpath to ESP_ROOT/lib on DARWIN — galbramc / detail
  35. numpy memory leak suppression — galbramc / detail
  36. Upgrade to AFLR 11.3.15 — galbramc / detail
  37. Add NETCDFINC for DARWIN64.gcc testing. — galbramc / detail
  38. Don't build AFLR with Beta testing — galbramc / detail

#175 (Jan 14, 2023, 10:32:25 AM)

  1. small fix to morph test — ryan / detail
  2. small fix to morph test — ryan / detail
  3. Tex fix for training — galbramc / detail
  4. Training updates — galbramc / detail
  5. Training fixes and updates — galbramc / detail
  6. Lint fix — galbramc / detail
  7. Fix last commit — galbramc / detail
  8. Fully support 2D meshes for plato and exodus mesher writer — galbramc / detail
  9. Add missing avl derivatives — galbramc / detail
  10. Another round of training updates — galbramc / detail
  11. lint fix — galbramc / detail
  12. Comment on F_UFMTENDIAN environment variable if msesAIM fails to read mses sensx file. — galbramc / detail
  13. Add support for 2D meshes with exodusWriter — galbramc / detail
  14. One more training update — galbramc / detail
  15. Training tex updates — galbramc / detail
  16. Minor training fixes and updates — galbramc / detail
  17. Remove old training files. Some training tex fixes. — galbramc / detail
  18. Update date on training slides — galbramc / detail
  19. Add training tar script — galbramc / detail
  20. Corrections to CAPS session01 — galbramc / detail
  21. Missed a file — galbramc / detail
  22. Updated CAPS training for Jan 2023 — galbramc / detail
  23. update copyright notices — jfdannen / detail
  24. add transform option to Slugs; in Slugs, the KutTriangles option automatically creates a link; add optional GRAFIC to cutTriangles in Slugs; lots of improvements to Slugs, especially for cases with very noisy .stl file — jfdannen / detail
  25. Update Copyright date — galbramc / detail
  26. fix bug that did not allow interactive use of Slugs; add Kut triangles option in Slugs; update testScript.txt to include interactive Slugs testing — jfdannen / detail
  27. Fix surface to volume map for MultiDomain tetgen meshes — galbramc / detail
  28. Uprev to 1.23 — galbramc / detail
  29. update copyright notices — jfdannen / detail
  30. uprev to v1.23 (ESP.html, ESP-localhost.html, ESP-help.html, OpenCSM.h, ocsm.rc) — jfdannen / detail
  31. Update Copyright date — galbramc / detail
  32. Uprev to 1.23 — galbramc / detail

#174 (Dec 10, 2022, 7:42:26 AM)

  1. dox fix — ryan / detail
  2. Add TACS and MSES to AIM documentation — galbramc / detail
  3. Check for nPoints==0 when filling bounds — galbramc / detail
  4. Check if no bodies have capsDiscipline Structure — galbramc / detail
  5. put 1 second delay when opening a pyscript to make sure that the browser is ready to display the pyscript in the editor; do not change status of ESP if an error was found while executing a pyscript; update session10 training files to be consistent with new method for creating a large, multi-component, multi-discipline model; update Makefile.DARWIN64; update ESP_QuickReference; update testScript.txt — jfdannen / detail
  6. update error handling in flapz.udc; first attempt at python files for new transport for CAPS training — jfdannen / detail
  7. README release notes updates — galbramc / detail

#173 (Dec 3, 2022, 2:19:32 PM)

  1. Rev update and other dox fixes — galbramc / detail
  2. More VLM error handling updates — galbramc / detail
  3. Update documentation for masstran. Update VLM input error messages. — galbramc / detail
  4. Use the body _name if there is only one body in exodus writer — galbramc / detail
  5. Initial commit of 2023 training — galbramc / detail
  6. add comments to cyli_box.csm — jfdannen / detail
  7. unset LD_PRELOAD when checking NETCDFINC — galbramc / detail
  8. Another debug attempt — galbramc / detail
  9. Debugging exodus makefile — galbramc / detail
  10. change sprintf to snprintf in Slugs — jfdannen / detail
  11. Missed one — galbramc / detail
  12. More example updates — galbramc / detail
  13. Replace last sprintf with snprintf — galbramc / detail
  14. fix examples — ryan / detail
  15. fix examples — ryan / detail
  16. Fix double free in astrosAIM — galbramc / detail
  17. Updated config file generator for SU2-7.4.0 — nitin / detail
  18. Warning fix. Double memory free fix. More sprintf replacements. — galbramc / detail
  19. Replace aim sprintf with snprintf — galbramc / detail
  20. scan-build fix — galbramc / detail
  21. Windoze fix — galbramc / detail
  22. masstran now supports analysis sensitvities — galbramc / detail
  23. More example updates for new structures design variable relations — galbramc / detail
  24. Fix for old training — galbramc / detail
  25. Lots of lint fixes — galbramc / detail
  26. Fix array bounds erros and update tests for new structures design variables — galbramc / detail
  27. scan-build fixes — galbramc / detail
  28. Fix legacy example — galbramc / detail
  29. Warning fix — galbramc / detail
  30. Fix previous commits. Add more info in caps_setValue error message. masstranAIM fix. — galbramc / detail
  31. fix of design variables — ryan / detail
  32. fix of design variables — ryan / detail
  33. fix of design variables — ryan / detail
  34. fix of design variables — ryan / detail
  35. add cvxopt debug messages — dongjoon / detail
  36. add more debugging statements — dongjoon / detail
  37. add debugging corsairlite statements
    dongjoon / detail
  38. update corsairlite example for debugging — dongjoon / detail
  39. scan-build fixes — galbramc / detail
  40. Suppress warning — galbramc / detail
  41. Update cyli_box example with semi-colon separated capsGroup tags — galbramc / detail
  42. account for forward- and backward-slashes when opening a .udc — jfdannen / detail
  43. update ereped6a and project verification data again; fix recently-added bug that causes a memory fault for some non-manifold Edges — jfdannen / detail
  44. add Trace button in .csm editor to trace all top-level Parameters; reorganize session10 files to make it easier to build large, multi-component, multi-view models; update ereped6a, hollowC6, hollowC7, hollowCA, hollowCB, and project 3 verification data on 7.6.0 (because of issues highlighted by Xcode 14 on M1); update ereped6a and project3 verification data on 7.4.1 (because of issues highlighted by Xcode 14 on M1); add description of -dxdd flag to ESP-help — jfdannen / detail
  45. update testScript.txt; fix possible buffer overflow in SPECIAL command — jfdannen / detail
  46. convert all (deprecated) sprintf calls to snprintf — jfdannen / detail
  47. fix bug where result of SPECIAL/clearance was not recycled — jfdannen / detail
  48. remove suppressions of sensitivity checks on designH2, designJ1c, designJ1d, and designJ5; add suppressions of sensitivity checks to designG5 and designG6 (for rounded tips); fix valgrind error in sensitivities in udpWaffle — jfdannen / detail
  49. fix some compiler warnings in most recent commit — jfdannen / detail
  50. add ocsmClearance; add clearance* test cases — jfdannen / detail
  51. Rev updates to 1.22 — galbramc / detail
  52. README updates — galbramc / detail
  53. Update makeEnv for macOS 13 — galbramc / detail
  54. Replace DEBUG sprintf with snprintf — galbramc / detail
  55. Try again: reorder includes! — haimes / detail
  56. Try again: MSVC 2022 seems to have snprintf defined! — haimes / detail
  57. sprintf -> snprintf mods — haimes / detail
  58. Replace sprintf with snprintf in egadsTopo — galbramc / detail
  59. Suppress clang deprication warning of sprintf in OCC — galbramc / detail
  60. Another exodus suppression — galbramc / detail
  61. Suppresse NETCDF/HDF5 memory leaks — galbramc / detail
  62. Upgrade to SU2 7.4.0 — galbramc / detail

#172 (Nov 12, 2022, 7:17:37 AM)

  1. Add print statements for debugging — dongjoon / detail
  2. add more debugOutput statements to show timing in SLCP — dongjoon / detail
  3. Fix skipping geometry Design_Variable in TACS — galbramc / detail
  4. More attempts at fixing the exodus makefile — galbramc / detail
  5. Stanalizer fix — galbramc / detail
  6. Finally got netcdf.h check correct on both macOS and Linux — galbramc / detail
  7. Another sanitizer fix — galbramc / detail
  8. sanitizer fixes — galbramc / detail
  9. Check for exodusWriter when running plato examples — galbramc / detail
  10. Write out surface to volume index map for plato — galbramc / detail
  11. Lint fix for mses — galbramc / detail
  12. Fix output redirect for detecing netcdf.h — galbramc / detail
  13. Update fun3d test to Mesh_Morph. Add first plato mesh generation examples. — galbramc / detail
  14. Allow tetgen to write MultiDomain mesh files. Updates to Exodus mesh writer. — galbramc / detail
  15. More checks when reading mapbc files in aimMesh — galbramc / detail
  16. Fun3D lint fixes — galbramc / detail
  17. fix - unused variables — ryan / detail
  18. fix - null catch in avlaim — ryan / detail
  19. fix fun3d morphing — ryan / detail
  20. Lint fixes — galbramc / detail
  21. Warning fix — galbramc / detail
  22. Fix last commit — galbramc / detail
  23. Fix waring and add missing files — galbramc / detail
  24. Support tetgen generated regions — galbramc / detail
  25. More lint fixes — galbramc / detail
  26. Fix lint warnings — galbramc / detail
  27. Update Makefile for plato. Add element group names for aflr3 and tetgen. — galbramc / detail
  28. Add plato skeleton AIM — galbramc / detail
  29. Initial cut at an exodus writer — galbramc / detail
  30. Fix for incorrect Design_Variable in masstranAIM — galbramc / detail
  31. Allow unconverged SmoothUV status to continue during parameterization — haimes / detail
  32. Fix masstran derivatives with multiple bodies — galbramc / detail
  33. Fix closeBound to write bound and vertexset files for journaling — haimes / detail
  34. fix typo in corsairlite slcp — dongjoon / detail
  35. delete redundant kulfan csm and finalize multifidelity scripts — dongjoon / detail
  36. Fix warnings from last commit — galbramc / detail
  37. small fix on Kulfan MSES wrapper and removing remnants of full corsair — dongjoon / detail
  38. Remove some depricated checks — galbramc / detail
  39. Journal the writing of files — haimes / detail
  40. Move up setting outLevel — galbramc / detail
  41. Use ocsmLoadFromModel for static geometry. Expost stepSize for finite differnce in pyCAPS. — galbramc / detail
  42. Add the ability to control the sensitivity finite-difference step size from CAPS proper — haimes / detail
  43. Remove old html doc before copying — galbramc / detail
  44. Update cart3dAIM dox — galbramc / detail
  45. Update pyCAPS dox dependencies — galbramc / detail
  46. update corsairlite files to python3.8 compatible — dongjoon / detail
  47. Use TIM viewer in pyCAPS view methods — galbramc / detail
  48. Allow ftype=None for FieldIn/FieldOut data sets — galbramc / detail
  49. fix bug in serveESP that did not properly update the build status message after File->Edit->Save; implement analytic sensitivities in udpWaffle; add designX* test cases; make sure userPointer gets reset after perturbation is removed — jfdannen / detail
  50. add ocsmAdjoint and testOcsmAdjoint (in serveESP); allow timPlotter to have two y-axes; add plotter3.py test case — jfdannen / detail
  51. update adjoint test to remove (incorrect) compiler warning — jfdannen / detail
  52. remove data/ide (because it is redundant with data/tutorial6); eliminate automatic build when entering CAPS mode (depend on the lazy evaluation in CAPS); enable sensitivity calculations for scribes and trims; add designW* test cases; fix bug that put wrong _edgeID on scribed Edges; update attrScribe, scribeWing, and scribedSphere test cases; create splitEdges.udc; add splitEdges* test cases — jfdannen / detail
  53. remember name of Pyscript file for next Tool->Pyscript; clean up ESP messages after builds; remove code in esp.timSetCaps that removed the _finalize method; fix memory problem in timViewer for very long scene-graph meta-data buffers; reset magic number to zero to catch cases when a MODL is tried to be used after ocsmFree; modify IMPORT so that it properly marks NODE_BODYs; force tessellation if needed in timViewer; fix bug in ocsmLoadFromEgads that did not properly initialize the .ileft and .irite Branches; remove underscore attributes in .egads files in ocsmLoadFromEgads; force python garbage collection at end of each pyscript execution; add interactive testScript — jfdannen / detail
  54. add PLOT_TESSSENS and PLOT_TEMPCOMPS flags to help in debugging tessellation sensitivities; remove tessellation velocity calculation shortcut to make Edge and Face tessellation velocities consistent; refactor signalError() and signalError2(); allow plotTypes =7 for x-component, =8 for y-component, =9 for z-component of sensitivity — jfdannen / detail
  55. Add simple figure for tri ordering with mixed quad faces — galbramc / detail
  56. Allow unconverged SmoothUV status to continue during parameterization — haimes / detail
  57. More general ubuntu suppression — galbramc / detail
  58. Ubuntu valgrid supression — galbramc / detail
  59. scipy 1.9.2. and 1.9.3 have valgrind issues — galbramc / detail
  60. Add seacas to macys — galbramc / detail
  61. Add SEACAS environment variable for exodus — galbramc / detail
  62. Upgrade cvxopt build for gcc 12 on viggen — galbramc / detail

#171 (Oct 8, 2022, 2:51:45 PM)

  1. update corsairlite slcp wrapper with speed-up updates — dongjoon / detail
  2. Move DESPMTR check into just TACS — galbramc / detail
  3. Don't write DESPMTR to bdf files — galbramc / detail
  4. Fix segFault from last commit, again — haimes / detail
  5. Fix segFault from last commit — haimes / detail
  6. First cut at using MD5 checksums to check API inputs for continuation mode — haimes / detail
  7. Fix masstran memory leak — galbramc / detail
  8. masstran AIM updates — galbramc / detail
  9. Another OCSM FD sensitivity update — haimes / detail
  10. The calling sequence (SetDtime) was wrong and should be after setting the parameter when calculating sensitivities — haimes / detail
  11. add some debugging output capabilities to corsairlite and properly pass problemObj in Kulfan.py — dongjoon / detail
  12. Compile fix for Windoze — galbramc / detail
  13. Fix continuation with a function that returned an error — galbramc / detail
  14. Fix memory leak — galbramc / detail
  15. Fix masstran units and warning — galbramc / detail
  16. Update aim_copyValue — galbramc / detail
  17. Add geometric sensitvities to masstran AIM — galbramc / detail
  18. Suppress 'could not create compact unwind on M1' for now. — galbramc / detail
  19. Allow for FD sensitivities within the AIM sensitivity functions — haimes / detail
  20. add torch tests for kulfan corsairlite examples — dongjoon / detail
  21. update problem.__init__ to work if running pyscript but not from capsMode — jfdannen / detail
  22. Simplify multifidelity examples. Fig unit bug in caps.py. Support pint dimensionless to caps.py. Support udunits import in corsairlite. — galbramc / detail
  23. Fix typo in comment — haimes / detail
  24. Fix multifidelity corsairlite examples — dongjoon / detail
  25. Another cart3d twist example fix — galbramc / detail
  26. Cart3D example fixes — galbramc / detail
  27. Support Cart3D preSpec inputs and bodies. — galbramc / detail
  28. Forgot the pickle — galbramc / detail
  29. One more makefile fix — galbramc / detail
  30. corsair lite makefile example fix — galbramc / detail
  31. Dissable failing corsair examples again — galbramc / detail
  32. Fix corsairlite execution script — galbramc / detail
  33. Fix uninitialized journaling — galbramc / detail
  34. Run all phasing examples for corsairlite — galbramc / detail
  35. corsair fix for Python 3.10. Minor pyCAPS warning fix. — galbramc / detail
  36. Fix scan-build warning — galbramc / detail
  37. Fix for aim_relPath. Fix for sheet bodies with aim_storeMeshRef. — galbramc / detail
  38. fix morph example — ryan / detail
  39. Fix last commit — galbramc / detail
  40. Fix pyCAPS getValue for string and pointers — galbramc / detail
  41. Fix destroy_aimStorage to resolve segfault — galbramc / detail
  42. lint fixes — galbramc / detail
  43. I think we have mighty morphing powers — galbramc / detail
  44. test/fix morph — ryan / detail
  45. Skip wake with morphing for now. — galbramc / detail
  46. Fixes for mighty morphing powers, still needs some more testing. — galbramc / detail
  47. fix missing file — ryan / detail
  48. fix missing file — ryan / detail
  49. // This software has been cleared for public release on 05 Nov 2020, case number 88ABW-2020-3462.

    #include <string.h>
    #include <stdio.h>
    #include <errno.h>
    #include <ctype.h>

    #include "egads.h"        // Bring in egads utilss
    #include "capsTypes.h"    // Bring in CAPS types
    #include "aimUtil.h"      // Bring in AIM utils
    #include "aimMesh.h"      // Bring in AIM meshing

    #include "miscUtils.h"    // Bring in misc. utility functions
    #include "meshUtils.h"    // Bring in meshing utility functions
    #include "cfdTypes.h"     // Bring in cfd specific types
    #include "cfdUtils.h"
    #include "tecplotUtils.h" // Bring in tecplot utility functions
    #include "fun3dUtils.h"   // Bring in fun3d utility header
    #include "fun3dInputs.h"
    #include "ugridWriter.h"


    #ifdef WIN32
    #define strcasecmp  stricmp
    #define strncasecmp _strnicmp
    #endif


    // Extract the FEPOINT Tecoplot data from a FUN3D Aero-Loads file (connectivity is ignored) - dataMatrix = [numVariable][numDataPoint]
    int fun3d_readAeroLoad(void *aimInfo, char *filename, int *numVariable, char **variableName[],
                           int *numDataPoint, double ***dataMatrix)
    {

        int status = CAPS_SUCCESS; // Function return
        int i, j; // Indexing

        size_t linecap = 0;

        char *line = NULL; // Temporary line holder
        char *tempStr = NULL, *tempStr2 = NULL; // Temporary strings
        int stringLen = 0; // Length of string holder

        FILE *fp = NULL; // File pointer

        // Open file
        fp = aim_fopen(aimInfo, filename, "r");
        if (fp == NULL) {
            AIM_ERROR(aimInfo, "Unable to open file: %s\n", filename);
            return CAPS_IOERR;
        }

        printf("Reading FUN3D AeroLoad File - %s!!!!!!\n", filename);

        *numVariable = 0;
        *numDataPoint = 0;
        // Loop through file line by line until we have determined how many variables and data points there are
        while (*numVariable == 0 || *numDataPoint == 0) {

            // Get line from file
            status = getline(&line, &linecap, fp);
            if ((status < 0) || (line == NULL)) break;

            // Get variable list if available in file line
            if (strncmp("variables=", line, strlen("variables=")) == 0) {

                // Pull out substring at first occurrence of "
                tempStr = strstr(line, "\"");

                // Create a temperory string of the variables in a the folling format - ["a","ae"]
                stringLen  = strlen(tempStr)-1 + 2;

                tempStr2 = (char *) EG_alloc((stringLen +1)*sizeof(char *));
                if (tempStr2 == NULL) {
                    fclose(fp);
                    if (line != NULL) EG_free(line);
                    return EGADS_MALLOC;
                }

                tempStr2[0] = '[';
                strncpy(tempStr2+1, tempStr, strlen(tempStr)-1);
                tempStr2[stringLen-1] = ']';
                tempStr2[stringLen] = '\0';

                // Sort string into an array of strings
                status =  string_toStringDynamicArray(tempStr2, numVariable, variableName);

                if (tempStr2 != NULL) EG_free(tempStr2);
                tempStr2 = NULL;

                if (status != CAPS_SUCCESS) goto cleanup;

                // Print out list of variables found in load file
                printf("Variables found in file %s:\n",filename);
                for (i = 0; i < *numVariable; i++) printf("Variable %d = %s\n", i, (*variableName)[i]);
            }

            // Get the number of data points in file if available in file line
            if (strncmp("zone t=", line, strlen("zone t=")) == 0) {

                // Pull out substring at first occurrence of i=
                tempStr = strstr(line, "i=");

                // Retrieve the i= value
                sscanf(&tempStr[2], "%d", numDataPoint);

                // Print out the number of data points found in load file
                printf("Number of data points = %d, in file %s\n", *numDataPoint, filename);
            }

        }

        if (*numVariable != 0 && *numDataPoint != 0) {

            // Allocate dataMatrix array
            AIM_FREE(*dataMatrix);

            AIM_ALLOC(*dataMatrix, (*numVariable), double *, aimInfo, status);
            for (i = 0; i < *numVariable; i++) (*dataMatrix)[i] = NULL;

            for (i = 0; i < *numVariable; i++) {
                AIM_ALLOC((*dataMatrix)[i], (*numDataPoint), double, aimInfo, status);
            }

            // Loop through the file and fill up the data matrix
            for (j = 0; j < *numDataPoint; j++) {
                for (i = 0; i < *numVariable; i++) {
                    fscanf(fp, "%lf", &(*dataMatrix)[i][j]);
                }
            }

            // Output the first row of the dataMatrix
            //for (i = 0; i < *numVariable; i++) printf("Variable %d - %.6f\n", i, (*dataMatrix)[i][0]);

        } else {

            printf("No data values extracted from file - %s",filename);
            status = CAPS_BADVALUE;
        }

    cleanup:
        if (fp != NULL) fclose(fp);

        if (status != CAPS_SUCCESS) {
          if (*dataMatrix != NULL) {
            for (j = 0; j < *numVariable; j++) {
              AIM_FREE((*dataMatrix)[j]);
            }
            AIM_FREE((*dataMatrix));
          }
        }

        EG_free(line);
        return status;
    }


    static int
    fun3d_read2DBinaryUgrid(void *aimInfo, FILE *fp, meshStruct *surfaceMesh)
    {
      int    status = CAPS_SUCCESS;

      int    numNode, numLine, numTriangle, numQuadrilateral;
      int    numTetrahedral, numPyramid, numPrism, numHexahedral;
      int    i, elementIndex, numPoint, bcID;
      double *coords = NULL;

      /* we get a binary UGRID file */
      status = fread(&numNode,          sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
      status = fread(&numTriangle,      sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
      status = fread(&numQuadrilateral, sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
      status = fread(&numTetrahedral,   sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
      status = fread(&numPyramid,       sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
      status = fread(&numPrism,         sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
      status = fread(&numHexahedral,    sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

      if ( numTetrahedral   +
           numPyramid       +
           numPrism         +
           numHexahedral  > 0) {
        AIM_ERROR(aimInfo, "Expecting a 2D ugrid file!!!");
        status = CAPS_IOERR;
        goto cleanup;
      }

      /*
      printf("\n Header from UGRID file: %d  %d %d  %d %d %d %d\n", numNode,
             numTriangle, numQuadrilateral, numTetrahedral, numPyramid, numPrism,
             numHexahedral);
       */

      AIM_ALLOC(coords, 3*numNode, double, aimInfo, status);

      /* read all of the vertices */
      status = fread(coords, sizeof(double), 3*numNode, fp);
      if (status != 3*numNode) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

      surfaceMesh->analysisType = UnknownMeshAnalysis;

      // Set that this is a volume mesh
      surfaceMesh->meshType = Surface2DMesh;

      // Numbers
      surfaceMesh->numNode = numNode;
      surfaceMesh->numElement = numTriangle + numQuadrilateral;

      surfaceMesh->meshQuickRef.useStartIndex = (int) true;

      surfaceMesh->meshQuickRef.numTriangle      = numTriangle;
      surfaceMesh->meshQuickRef.numQuadrilateral = numQuadrilateral;

      // Nodes - allocate
      AIM_ALLOC(surfaceMesh->node, surfaceMesh->numNode, meshNodeStruct, aimInfo, status);

      // Initialize
      for (i = 0; i < surfaceMesh->numNode; i++) {
          status = initiate_meshNodeStruct(&surfaceMesh->node[i],
                                            surfaceMesh->analysisType);
          AIM_STATUS(aimInfo, status);
      }

      // Nodes - set
      for (i = 0; i < surfaceMesh->numNode; i++) {

        // Copy node data
        surfaceMesh->node[i].nodeID = i+1;

        surfaceMesh->node[i].xyz[0] = coords[3*i+0];
        surfaceMesh->node[i].xyz[1] = coords[3*i+1];
        surfaceMesh->node[i].xyz[2] = coords[3*i+2];
      }
      AIM_FREE(coords);

      // Elements - allocate
      AIM_ALLOC(surfaceMesh->element, surfaceMesh->numElement, meshElementStruct, aimInfo, status);

      // Initialize
      for (i = 0; i < surfaceMesh->numElement; i++ ) {
          status = initiate_meshElementStruct(&surfaceMesh->element[i],
                                               surfaceMesh->analysisType);
          AIM_STATUS(aimInfo, status);
      }

      // Start of element index
      elementIndex = 0;

      // Elements -Set triangles
      if (numTriangle > 0)
        surfaceMesh->meshQuickRef.startIndexTriangle = elementIndex;

      numPoint = mesh_numMeshConnectivity(Triangle);
      for (i = 0; i < numTriangle; i++) {

          surfaceMesh->element[elementIndex].elementType = Triangle;
          surfaceMesh->element[elementIndex].elementID   = elementIndex+1;

          status = mesh_allocMeshElementConnectivity(&surfaceMesh->element[elementIndex]);
          if (status != CAPS_SUCCESS) goto cleanup;

          // read the element connectivity
          status = fread(surfaceMesh->element[elementIndex].connectivity,
                         sizeof(int), numPoint, fp);
          if (status != numPoint) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

          elementIndex += 1;
      }

      // Elements -Set quadrilateral
      if (numQuadrilateral > 0)
        surfaceMesh->meshQuickRef.startIndexQuadrilateral = elementIndex;

      numPoint = mesh_numMeshConnectivity(Quadrilateral);
      for (i = 0; i < numQuadrilateral; i++) {

          surfaceMesh->element[elementIndex].elementType = Quadrilateral;
          surfaceMesh->element[elementIndex].elementID   = elementIndex+1;

          status = mesh_allocMeshElementConnectivity(&surfaceMesh->element[elementIndex]);
          if (status != CAPS_SUCCESS) goto cleanup;

          // read the element connectivity
          status = fread(surfaceMesh->element[elementIndex].connectivity,
                         sizeof(int), numPoint, fp);
          if (status != numPoint) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

          elementIndex += 1;
      }

      // skip face ID section of the file
      status = fseek(fp, (numTriangle + numQuadrilateral)*sizeof(int), SEEK_CUR);
      if (status != 0) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

      // Get the number of Line elements
      status = fread(&numLine, sizeof(int), 1, fp);
      if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

      // Elements - re-allocate with Line elements
      surfaceMesh->meshQuickRef.numLine = numLine;
      AIM_REALL(surfaceMesh->element, surfaceMesh->numElement+numLine, meshElementStruct, aimInfo, status);

      surfaceMesh->meshQuickRef.startIndexLine = elementIndex;

      // Initialize
      for (i = surfaceMesh->numElement; i < surfaceMesh->numElement+numLine; i++ ) {
          status = initiate_meshElementStruct(&surfaceMesh->element[i],
                                               surfaceMesh->analysisType);
          AIM_STATUS(aimInfo, status);
      }
      surfaceMesh->numElement += numLine;

      numPoint = mesh_numMeshConnectivity(Line);
      for (i = 0; i < numLine; i++) {

        surfaceMesh->element[elementIndex].elementType = Line;
        surfaceMesh->element[elementIndex].elementID   = elementIndex+1;

        status = mesh_allocMeshElementConnectivity(&surfaceMesh->element[elementIndex]);
        AIM_STATUS(aimInfo, status);

        // read the element connectivity
        status = fread(surfaceMesh->element[elementIndex].connectivity,
                       sizeof(int), numPoint, fp);
        if (status != numPoint) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }
        status = fread(&bcID, sizeof(int), 1, fp);
        if (status != 1) { status = CAPS_IOERR; AIM_STATUS(aimInfo, status); }

        surfaceMesh->element[elementIndex].markerID = bcID;

        elementIndex += 1;
      }

      status = CAPS_SUCCESS;

      cleanup:
          if (status != CAPS_SUCCESS)
            printf("Premature exit in getUGRID status = %d\n", status);

          EG_free(coords); coords = NULL;

          return status;
    }


    // Create a 3D BC for FUN3D from a 2D mesh
    int fun3d_2DBC(void *aimInfo,
                   cfdBoundaryConditionStruct *bcProps)
    {
        int status; // Function return status

        int i; // Indexing

        int faceBCIndex = -1, extrusionBCIndex = -1;

        // Find the faceBCIndex for the symmetry plane
        for (i = 0; i < bcProps->numSurfaceProp-1; i++) {
          if (bcProps->surfaceProp[i].surfaceType == Symmetry) {
            faceBCIndex = bcProps->surfaceProp[i].bcID;
            break;
          }
        }

        if (faceBCIndex == -1) {
          // Add plane boundary condition
          AIM_REALL(bcProps->surfaceProp, bcProps->numSurfaceProp+1, cfdSurfaceStruct, aimInfo, status);
          bcProps->numSurfaceProp += 1;

          status = initiate_cfdSurfaceStruct(&bcProps->surfaceProp[bcProps->numSurfaceProp-1]);
          AIM_STATUS(aimInfo, status);

          bcProps->surfaceProp[bcProps->numSurfaceProp-1].surfaceType = Symmetry;
          bcProps->surfaceProp[bcProps->numSurfaceProp-1].symmetryPlane = 1;

          // Find largest index value for bcID and set it plus 1 to the new surfaceProp
          for (i = 0; i < bcProps->numSurfaceProp-1; i++) {
              if (bcProps->surfaceProp[i].bcID >= faceBCIndex) {
                faceBCIndex = bcProps->surfaceProp[i].bcID + 1;
              }
          }
          bcProps->surfaceProp[bcProps->numSurfaceProp-1].bcID = faceBCIndex;
        }


        // Add extruded plane boundary condition
        AIM_REALL(bcProps->surfaceProp, bcProps->numSurfaceProp+1, cfdSurfaceStruct, aimInfo, status);
        bcProps->numSurfaceProp += 1;

        status = initiate_cfdSurfaceStruct(&bcProps->surfaceProp[bcProps->numSurfaceProp-1]);
        AIM_STATUS(aimInfo, status);

        bcProps->surfaceProp[bcProps->numSurfaceProp-1].surfaceType = Symmetry;
        bcProps->surfaceProp[bcProps->numSurfaceProp-1].symmetryPlane = 2;

        // Find largest index value for bcID and set it plus 1 to the new surfaceProp
        for (i = 0; i < bcProps->numSurfaceProp-1; i++) {
            if (bcProps->surfaceProp[i].bcID >= extrusionBCIndex) {
              extrusionBCIndex = bcProps->surfaceProp[i].bcID + 1;
            }
        }
        bcProps->surfaceProp[bcProps->numSurfaceProp-1].bcID = extrusionBCIndex;

        status = CAPS_SUCCESS;

    cleanup:
        return status;
    }


    // Create a 3D mesh for FUN3D from a 2D mesh
    int fun3d_2DMesh(void *aimInfo,
                     aimMeshRef *meshRef,
                     const char *projectName,
                     const mapAttrToIndexStruct *groupMap)
    {

        int status; // Function return status

        int i; // Indexing

        int faceBCIndex = -1, extrusionBCIndex = -1;

        double extrusion = -1.0; // Extrusion length

        // Flip coordinates
        int xMeshConstant = (int) true, yMeshConstant = (int) true, zMeshConstant= (int) true; // 2D mesh checks
        double tempCoord;

        meshStruct surfaceMesh;
        meshStruct volumeMesh;

        char filename[PATH_MAX];
    //    int elementIndex;
        FILE *fp = NULL;

        status = initiate_meshStruct(&surfaceMesh);
        AIM_STATUS(aimInfo, status);

        status = initiate_meshStruct(&volumeMesh);
        AIM_STATUS(aimInfo, status);

        sprintf(filename, "%s%s", meshRef->fileName, MESHEXTENSION);

        fp = fopen(filename, "rb");
        if (fp == NULL) {
          AIM_ERROR(aimInfo, "Cannot open file: %s\n", filename);
          status = CAPS_IOERR;
          goto cleanup;
        }

        status = fun3d_read2DBinaryUgrid(aimInfo, fp, &surfaceMesh);
        AIM_STATUS(aimInfo, status);

        // add boundary elements if they are missing
        if (surfaceMesh.meshQuickRef.numLine == 0) {
            status = mesh_addTess2Dbc(aimInfo, &surfaceMesh, groupMap);
            if (status != CAPS_SUCCESS) goto cleanup;
        }

        // Set the symmetry index for all Tri/Quad
        for (i = 0; i < surfaceMesh.numElement; i++) {

            if (surfaceMesh.element[i].elementType != Triangle &&
                surfaceMesh.element[i].elementType != Quadrilateral) {
                continue;
            }

            surfaceMesh.element[i].markerID = faceBCIndex;
        }

    #ifdef I_DONT_THINK_WE_NEED_THIS
        // Determine a suitable boundary index of the extruded plane
        *extrusionBCIndex = faceBCIndex;
        for (i = 0; i < surfaceMesh.meshQuickRef.numLine; i++) {

            if (surfaceMesh.meshQuickRef.startIndexLine >= 0) {
                elementIndex = surfaceMesh.meshQuickRef.startIndexLine + i;
            } else {
                elementIndex = surfaceMesh.meshQuickRef.listIndexLine[i];
            }

            marker = surfaceMesh.element[elementIndex].markerID;

            if (marker > *extrusionBCIndex)  {
                *extrusionBCIndex = marker;
            }
        }
        *extrusionBCIndex += 1;
    #endif

        // Check to make sure the face is on the y = 0 plane
        for (i = 0; i < surfaceMesh.numNode; i++) {

            if (surfaceMesh.node[i].xyz[1] != 0.0) {
                printf("\nSurface mesh is not on y = 0.0 plane, FUN3D could fail during execution for this 2D mesh!!!\n");
                break;
            }
        }

        // Constant x?
        for (i = 0; i < surfaceMesh.numNode; i++) {
            if ((surfaceMesh.node[i].xyz[0] - surfaceMesh.node[0].xyz[0]) > 1E-7) {
                xMeshConstant = (int) false;
                break;
            }
        }

        // Constant y?
        for (i = 0; i < surfaceMesh.numNode; i++) {
            if ((surfaceMesh.node[i].xyz[1] - surfaceMesh.node[0].xyz[1] ) > 1E-7) {
                yMeshConstant = (int) false;
                break;
            }
        }

        // Constant z?
        for (i = 0; i < surfaceMesh.numNode; i++) {
            if ((surfaceMesh.node[i].xyz[2] - surfaceMesh.node[0].xyz[2]) > 1E-7) {
                zMeshConstant = (int) false;
                break;
            }
        }

        if (yMeshConstant != (int) true) {
            printf("FUN3D expects 2D meshes be in the x-z plane... attempting to rotate mesh!\n");

            if (xMeshConstant == (int) true && zMeshConstant == (int) false) {
                printf("Swapping y and x coordinates!\n");
                for (i = 0; i < surfaceMesh.numNode; i++) {
                    tempCoord = surfaceMesh.node[i].xyz[0];
                    surfaceMesh.node[i].xyz[0] = surfaceMesh.node[i].xyz[1];
                    surfaceMesh.node[i].xyz[1] = tempCoord;
                }

            } else if(xMeshConstant == (int) false && zMeshConstant == (int) true) {

                printf("Swapping y and z coordinates!\n");
                for (i = 0; i < surfaceMesh.numNode; i++) {
                    tempCoord = surfaceMesh.node[i].xyz[2];
                    surfaceMesh.node[i].xyz[2] = surfaceMesh.node[i].xyz[1];
                    surfaceMesh.node[i].xyz[1] = tempCoord;
                }

            } else {
                AIM_ERROR(aimInfo, "Unable to rotate mesh!\n");
                status = CAPS_NOTFOUND;
                goto cleanup;
            }
        }

        status = extrude_SurfaceMesh(extrusion, extrusionBCIndex, &surfaceMesh, &volumeMesh);
        AIM_STATUS(aimInfo, status);

        strcpy(filename, projectName);

        // Write AFLR3
    /*@-nullpass@*/
         status = mesh_writeAFLR3(aimInfo, filename,
                                  0, // write binary file
                                  &volumeMesh,
                                  1.0);
    /*@+nullpass@*/
         AIM_STATUS(aimInfo, status);

        status = CAPS_SUCCESS;

    cleanup:
        if (status != CAPS_SUCCESS) {
            printf("Error: Premature exit in fun3d_2DMesh status = %d\n", status);
        }

    /*@-dependenttrans@*/
        if (fp != NULL) fclose(fp);
    /*@+dependenttrans@*/

        // Destroy meshes
        (void) destroy_meshStruct(&surfaceMesh);
        (void) destroy_meshStruct(&volumeMesh);

        return status;
    }


    // Remove unused nodes from dataMatrix and update connectivity matrix
    static int fun3d_removeUnused(void *aimInfo, int numVariable, int *numNode,  int used[],
                                  double ***data, /*@null@*/ int *numConnect,
                                  /*@null@*/ int *dataConnectMatrix)
    {
        int i, j, k; //Indexing
        int status;

        int *usedNode=NULL; // Freeable

        double **dataMatrix;

        dataMatrix = *data;

        // Copy used node array
        usedNode = (int *) EG_alloc(*numNode*sizeof(int));
        if (usedNode == NULL) {
            status = EGADS_MALLOC;
            goto cleanup;
        }
        for (i = 0; i < *numNode; i++) usedNode[i] = used[i];

        // Remove unused nodes
        j = 0;
        for (i = 0; i< *numNode; i++ ) {
            if (usedNode[i] == (int) false || usedNode[i] < 0) continue;

            usedNode[i] = j+1; // Set i-th node to essentially the node ID,  1-bias

            j +=1;
        }

        j = 0;
        for (i = 0; i< *numNode; i++ ) {
            if (usedNode[i] == (int) false || usedNode[i] < 0) continue;

            for (k = 0; k < numVariable; k++) {
                dataMatrix[k][j] = dataMatrix[k][i]; //Re-order dataMatrix - bubbling i'th index to j
            }

            j += 1;
        }

        *numNode = j; // New number of nodes

        // Redo connectivity
        if (dataConnectMatrix != NULL) {
            AIM_NOTNULL(numConnect, aimInfo, status);
            j = 0;
            for (i = 0; i < *numConnect; i++) {

                if (usedNode[dataConnectMatrix[4*i+ 0]-1] == (int) false) continue;
                if (usedNode[dataConnectMatrix[4*i+ 1]-1] == (int) false) continue;
                if (usedNode[dataConnectMatrix[4*i+ 2]-1] == (int) false) continue;
                if (usedNode[dataConnectMatrix[4*i+ 3]-1] == (int) false) continue;

                for (k = 0; k < 4; k++) {
                   dataConnectMatrix[4*j+ k] = usedNode[dataConnectMatrix[4*i+ k]-1];
                }

                j += 1;
            }

            *numConnect = j; // New number of elements
        }

        status = CAPS_SUCCESS;

    cleanup:
        if (status != CAPS_SUCCESS)
            printf("Error: Premature exit in fun3d_removeUnused status = %d\n",
                   status);

        if (usedNode != NULL) EG_free(usedNode);
        return status;
    }


    // Write FUN3D data transfer files
    int fun3d_dataTransfer(void *aimInfo,
                           const char *projectName,
                           const mapAttrToIndexStruct *groupMap,
                           const cfdBoundaryConditionStruct bcProps,
                           aimMeshRef *meshRef,
                           /*@null@*/ cfdModalAeroelasticStruct *eigenVector)
    {

        /*! \page dataTransferFUN3D FUN3D Data Transfer
         *
         * \section dataToFUN3D Data transfer to FUN3D (FieldIn)
         *
         * <ul>
         *  <li> <B>"Displacement"</B> </li> <br>
         *   Retrieves nodal displacements (as from a structural solver)
         *   and updates FUN3D's surface mesh; a new [project_name]_body1.dat file is written out which may
         *   be loaded into FUN3D to update the surface mesh/move the volume mesh using the FUN3D command line option
         *   -\-read_surface_from_file
         * </ul>
         *
         * <ul>
         *  <li> <B>"EigenVector_#"</B> </li> <br>
         *   Retrieves modal eigen-vectors from a structural solver, where "#" should be replaced by the
         *   corresponding mode number for the eigen-vector (eg. EigenVector_3 would correspond to the third mode,
         *   while EigenVector_6 would be the sixth mode) . A [project_name]_body1_mode#.dat file is written
         *   out for each mode.
         * </ul>
         *
         */

        int status; // Function return status
        int i, j, ibound, ibody, iface, iglobal, eigenIndex; // Indexing

        int stringLength = 0;

        char *filename = NULL;

        // Discrete data transfer variables
        capsDiscr *discr;
        char **boundName = NULL;
        int numBoundName = 0;
        enum capsdMethod dataTransferMethod;
        int numDataTransferPoint;
        int dataTransferRank;
        double *dataTransferData;
        char   *units;

        int state, nGlobal, *globalOffset=NULL, nFace;
        ego body, *faces=NULL;

        int alen, ntri, atype, itri, ielem;
        const double *face_xyz, *face_uv, *reals;
        const int *face_ptype, *face_pindex, *face_tris, *face_tric, *nquad=NULL;
        const char *string, *groupName = NULL;

        // Variables used in global node mapping
        int ptype, pindex;
        double xyz[3];

        // Data transfer Out variables
        const char *dataOutName[] = {"x","y","z", "id", "dx", "dy", "dz"};
        const int dataOutFormat[] = {Double, Double, Double, Integer, Double, Double, Double};

        double **dataOutMatrix = NULL;
        int *dataConnectMatrix = NULL;

        int numOutVariable = 7;
        int numOutDataPoint = 0;
        int numOutDataConnect = 0;

        const char fileExtBody[] = "_body1";
        const char fileExt[] = ".dat";
        const char fileExtMode[] = "_mode";

        int foundDisplacement = (int) false, foundEigenVector = (int) false;

        int marker;

        int numUsedNode = 0, numUsedConnectivity = 0, usedElems;
        int *usedNode = NULL;

        status = aim_getBounds(aimInfo, &numBoundName, &boundName);
        AIM_STATUS(aimInfo, status);

        foundDisplacement = foundEigenVector = (int) false;
        for (ibound = 0; ibound < numBoundName; ibound++) {
          AIM_NOTNULL(boundName, aimInfo, status);

          status = aim_getDiscr(aimInfo, boundName[ibound], &discr);
          if (status != CAPS_SUCCESS) continue;

          status = aim_getDataSet(discr,
                                  "Displacement",
                                  &dataTransferMethod,
                                  &numDataTransferPoint,
                                  &dataTransferRank,
                                  &dataTransferData,
                                  &units);

          if (status == CAPS_SUCCESS) { // If we do have data ready is the rank correct

            foundDisplacement = (int) true;

            if (dataTransferRank != 3) {
              AIM_ERROR(aimInfo, "Displacement transfer data found however rank is %d not 3!!!!\n", dataTransferRank);
              status = CAPS_BADRANK;
              goto cleanup;
            }
            break;
          }

          if (eigenVector != NULL) {
            for (eigenIndex = 0; eigenIndex < eigenVector->numEigenValue; eigenIndex++) {

              status = aim_getDataSet(discr,
                                      eigenVector->eigenValue[eigenIndex].name,
                                      &dataTransferMethod,
                                      &numDataTransferPoint,
                                      &dataTransferRank,
                                      &dataTransferData,
                                      &units);

              if (status == CAPS_SUCCESS) { // If we do have data ready is the rank correct

                foundEigenVector = (int) true;

                if (dataTransferRank != 3) {
                  AIM_ERROR(aimInfo, "EigenVector transfer data found however rank is %d not 3!!!!\n", dataTransferRank);
                  status = CAPS_BADRANK;
                  goto cleanup;
                }
                break;
              }
            } // Loop through EigenValues

            if (foundEigenVector == (int) true) break;

          } // If eigen-vectors provided
        } // Loop through transfer names

        if (foundDisplacement != (int) true && foundEigenVector != (int) true) {
          printf("Info: No recognized data transfer names found.\n");
          status = CAPS_NOTFOUND;
          goto cleanup;
        }

        // Ok looks like we have displacements/EigenVectors to get so lets continue
        printf("Writing FUN3D data transfer files\n");

        // Allocate data arrays that are going to be output
        AIM_ALLOC(dataOutMatrix, numOutVariable, double*, aimInfo, status);
        for (i = 0; i < numOutVariable; i++) dataOutMatrix[i] = NULL;

        AIM_ALLOC(globalOffset, meshRef->nmap+1, int, aimInfo, status);
        numOutDataPoint = 0;
        ielem = 0;
        globalOffset[0] = 0;
        for (i = 0; i < meshRef->nmap; i++) {
          if (meshRef->maps[i].tess == NULL) continue;

          status = EG_statusTessBody(meshRef->maps[i].tess, &body, &state, &nGlobal);
          AIM_STATUS(aimInfo, status);

          // re-allocate data arrays
          for (j = 0; j < numOutVariable; j++) {
            AIM_REALL(dataOutMatrix[j], numOutDataPoint + nGlobal, double, aimInfo, status);
          }
          AIM_REALL(usedNode, numOutDataPoint + nGlobal, int, aimInfo, status);
          for (j = globalOffset[0]; j < numOutDataPoint + nGlobal; j++) usedNode[j] = (int) false;


          for (iglobal = 0; iglobal < nGlobal; iglobal++) {
            status = EG_getGlobal(meshRef->maps[i].tess,
                                  iglobal+1, &ptype, &pindex, xyz);
            AIM_STATUS(aimInfo, status);

            // First just set the Coordinates
            dataOutMatrix[0][globalOffset[i]+iglobal] = xyz[0];
            dataOutMatrix[1][globalOffset[i]+iglobal] = xyz[1];
            dataOutMatrix[2][globalOffset[i]+iglobal] = xyz[2];

            // Volume mesh node ID
            dataOutMatrix[3][globalOffset[i]+iglobal] = meshRef->maps[i].map[iglobal];

            // Delta displacements
            dataOutMatrix[4][i] = 0;
            dataOutMatrix[5][i] = 0;
            dataOutMatrix[6][i] = 0;
          }

          // check if the tessellation has a mixture of quad and tess
          status = EG_attributeRet(meshRef->maps[i].tess, ".mixed",
                                   &atype, &alen, &nquad, &reals, &string);
          if (status != EGADS_SUCCESS &&
              status != EGADS_NOTFOUND) AIM_STATUS(aimInfo, status);

          status = EG_getBodyTopos(body, NULL, FACE, &nFace, &faces);
          AIM_STATUS(aimInfo, status);
          for (iface = 0; iface < nFace; iface++) {
            // get the face tessellation
            status = EG_getTessFace(meshRef->maps[i].tess, iface+1, &alen, &face_xyz, &face_uv,
                                    &face_ptype, &face_pindex, &ntri, &face_tris, &face_tric);
            AIM_STATUS(aimInfo, status);
            AIM_NOTNULL(faces, aimInfo, status);

            status = retrieve_CAPSGroupAttr(faces[iface], &groupName);
            if (status == EGADS_SUCCESS) {
              AIM_NOTNULL(groupName, aimInfo, status);
              status = get_mapAttrToIndexIndex(groupMap, groupName, &marker);
              if (status != CAPS_SUCCESS) {
                AIM_ERROR(aimInfo, "No capsGroup \"%s\" not found in attribute map", groupName);
                goto cleanup;
              }
            } else {
              AIM_ERROR(aimInfo, "No capsGroup on face %d", iface+1);
              print_AllAttr(aimInfo, faces[iface]);
              goto cleanup;
            }

            //  To keep with the moving_bodying input we will assume used nodes are all inviscid and viscous surfaces instead
            //                        usedNode[k] = (int) true;
            usedElems = (int) false;
            for (j = 0; j < bcProps.numSurfaceProp; j++) {
              if (marker != bcProps.surfaceProp[j].bcID) continue;

              if (bcProps.surfaceProp[j].surfaceType == Viscous ||
                  bcProps.surfaceProp[j].surfaceType == Inviscid) {
                  usedElems = (int) true;
              }
              break;
            }

            if (nquad == NULL) { // all triangles

              // re-allocate data arrays
              AIM_REALL(dataConnectMatrix, 4*(numOutDataConnect + ntri), int, aimInfo, status);

              for (itri = 0; itri < ntri; itri++, ielem++) {
                for (j = 0; j < 3; j++) {
                  status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+j], &iglobal);
                  AIM_STATUS(aimInfo, status);
                  dataConnectMatrix[4*ielem+j] = globalOffset[i] + iglobal;
                  usedNode[globalOffset[i]+iglobal-1] = usedElems;
                }
                // repeat the last node for triangles
                dataConnectMatrix[4*ielem+3] = dataConnectMatrix[4*ielem+2];
              }

              numOutDataConnect += ntri;

            } else { // mixture of tri and quad elements

              // re-allocate data arrays
              AIM_REALL(dataConnectMatrix, 4*(numOutDataConnect + ntri-nquad[iface]), int, aimInfo, status);

              // process triangles
              for (itri = 0; itri < ntri-2*nquad[iface]; itri++, ielem++) {
                for (j = 0; j < 3; j++) {
                  status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+j], &iglobal);
                  AIM_STATUS(aimInfo, status);
                  dataConnectMatrix[4*ielem+j] = globalOffset[i] + iglobal;
                  usedNode[globalOffset[i]+iglobal-1] = usedElems;
                }
                // repeat the last node for triangle
                dataConnectMatrix[4*ielem+3] = dataConnectMatrix[4*ielem+2];
              }
              // process quads
              for (; itri < ntri; itri++, ielem++) {
                for (j = 0; j < 3; j++) {
                  status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+j], &iglobal);
                  AIM_STATUS(aimInfo, status);
                  dataConnectMatrix[4*ielem+j] = globalOffset[i] + iglobal;
                  usedNode[globalOffset[i]+iglobal-1] = usedElems;
                }

                // add the last node from the 2nd triangle to make the quad
                itri++;
                status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+2], &iglobal);
                AIM_STATUS(aimInfo, status);
                dataConnectMatrix[4*ielem+3] = globalOffset[i] + iglobal;
                usedNode[globalOffset[i]+iglobal-1] = usedElems;
              }

              numOutDataConnect += ntri-nquad[iface];
            }

          }
          AIM_FREE(faces);

          numOutDataPoint += nGlobal;
          globalOffset[i+1] = globalOffset[i] + nGlobal;
        }

        // Re-loop through transfers - if we are doing displacements
        if (foundDisplacement == (int) true) {

          for (ibound = 0; ibound < numBoundName; ibound++) {
            AIM_NOTNULL(boundName, aimInfo, status);

            status = aim_getDiscr(aimInfo, boundName[ibound], &discr);
            if (status != CAPS_SUCCESS) continue;

            status = aim_getDataSet(discr,
                                    "Displacement",
                                    &dataTransferMethod,
                                    &numDataTransferPoint,
                                    &dataTransferRank,
                                    &dataTransferData,
                                    &units);
            if (status != CAPS_SUCCESS) continue; // If no elements in this object skip to next transfer name

            if (numDataTransferPoint != discr->nPoints &&
                numDataTransferPoint > 1) {
              AIM_ERROR(aimInfo, "Developer error!! %d != %d", numDataTransferPoint, discr->nPoints);
              status = CAPS_MISMATCH;
              goto cleanup;
            }

            for (i = 0; i < discr->nPoints; i++) {

              ibody   = discr->tessGlobal[2*i+0];
              iglobal = discr->tessGlobal[2*i+1];

              status = EG_getGlobal(discr->bodys[ibody-1].tess,
                                    iglobal, &ptype, &pindex, xyz);
              AIM_STATUS(aimInfo, status);

              // Find the disc tessellation in the original list of tessellations
              for (j = 0; j < meshRef->nmap; j++) {
                if (discr->bodys[ibody-1].tess == meshRef->maps[j].tess) {
                  break;
                }
              }
              if (j == meshRef->nmap) {
                AIM_ERROR(aimInfo, "Could not find matching tessellation!");
                status = CAPS_MISMATCH;
                goto cleanup;
              }

              if (numDataTransferPoint == 1) {
                // A single point means this is an initialization phase

                // Apply delta displacements
                dataOutMatrix[0][globalOffset[j]+iglobal-1] += dataTransferData[0];
                dataOutMatrix[1][globalOffset[j]+iglobal-1] += dataTransferData[1];
                dataOutMatrix[2][globalOffset[j]+iglobal-1] += dataTransferData[2];

                // save delta displacements
                dataOutMatrix[4][globalOffset[j]+iglobal-1] = dataTransferData[0];
                dataOutMatrix[5][globalOffset[j]+iglobal-1] = dataTransferData[1];
                dataOutMatrix[6][globalOffset[j]+iglobal-1] = dataTransferData[2];

              } else {
                // Apply delta displacements
                dataOutMatrix[0][globalOffset[j]+iglobal-1] += dataTransferData[3*i+0];
                dataOutMatrix[1][globalOffset[j]+iglobal-1] += dataTransferData[3*i+1];
                dataOutMatrix[2][globalOffset[j]+iglobal-1] += dataTransferData[3*i+2];

                dataOutMatrix[4][globalOffset[j]+iglobal-1] = dataTransferData[3*i+0];
                dataOutMatrix[5][globalOffset[j]+iglobal-1] = dataTransferData[3*i+1];
                dataOutMatrix[6][globalOffset[j]+iglobal-1] = dataTransferData[3*i+2];
              }
            }
          } // End numBoundName loop

          // Remove unused nodes
          numUsedNode = numOutDataPoint;
          numUsedConnectivity = numOutDataConnect;
          AIM_NOTNULL(usedNode, aimInfo, status);
          status = fun3d_removeUnused(aimInfo, numOutVariable, &numUsedNode, usedNode,
                                      &dataOutMatrix, &numUsedConnectivity,
                                      dataConnectMatrix);
          AIM_STATUS(aimInfo, status);

          stringLength = strlen(projectName) + strlen(fileExtBody) + strlen(fileExt) + 1;
          AIM_ALLOC(filename, stringLength+1, char, aimInfo, status);

          strcpy(filename, projectName);
          strcat(filename, fileExtBody);
          strcat(filename, fileExt);
          filename[stringLength] = '\0';

          // Write out displacement in tecplot file
          /*@-nullpass@*/
          status = tecplot_writeFEPOINT(aimInfo, filename,
                                        "FUN3D AeroLoads",
                                        NULL,
                                        numOutVariable,
                                        (char **)dataOutName,
                                        numUsedNode, // numOutDataPoint,
                                        dataOutMatrix,
                                        dataOutFormat,
                                        numUsedConnectivity, //numOutDataConnect, // numConnectivity
                                        dataConnectMatrix, // connectivity matrix
                                        NULL); // Solution time
          /*@+nullpass@*/
          AIM_STATUS(aimInfo, status);
          AIM_FREE(filename);
        } // End if found displacements

        // Re-loop through transfers - if we are doing eigen-vectors
        if ((foundEigenVector == (int) true) && (eigenVector != NULL)) {

          for (eigenIndex = 0; eigenIndex < eigenVector->numEigenValue; eigenIndex++) {

            // Zero out the eigen-vectors each time we are writing out a new one
            for (i = 0; i < numOutDataPoint; i++ ) {

              // Delta eigen-vectors
              dataOutMatrix[4][i] = 0;
              dataOutMatrix[5][i] = 0;
              dataOutMatrix[6][i] = 0;
            }

            for (ibound = 0; ibound < numBoundName; ibound++) {
              AIM_NOTNULL(boundName, aimInfo, status);

              status = aim_getDiscr(aimInfo, boundName[ibound], &discr);
              if (status != CAPS_SUCCESS) continue;

              status = aim_getDataSet(discr,
                                      eigenVector->eigenValue[eigenIndex].name,
                                      &dataTransferMethod,
                                      &numDataTransferPoint,
                                      &dataTransferRank,
                                      &dataTransferData,
                                      &units);
              if (status != CAPS_SUCCESS) continue; // If no elements in this object skip to next transfer name

              if (numDataTransferPoint != discr->nPoints &&
                  numDataTransferPoint > 1) {
                AIM_ERROR(aimInfo, "Developer error!! %d != %d", numDataTransferPoint, discr->nPoints);
                status = CAPS_MISMATCH;
                goto cleanup;
              }

              for (i = 0; i < discr->nPoints; i++) {

                ibody   = discr->tessGlobal[2*i+0];
                iglobal = discr->tessGlobal[2*i+1];

                // Find the disc tessellation in the original list of tessellations
                for (j = 0; j < meshRef->nmap; j++) {
                  if (discr->bodys[ibody-1].tess == meshRef->maps[j].tess) {
                    break;
                  }
                }
                if (j == meshRef->nmap) {
                  AIM_ERROR(aimInfo, "Could not find matching tessellation!");
                  status = CAPS_MISMATCH;
                  goto cleanup;
                }

                if (numDataTransferPoint == 1) {
                  // A single point means this is an initialization phase

                  // save Eigen-vector
                  dataOutMatrix[4][globalOffset[j]+iglobal-1] = dataTransferData[0];
                  dataOutMatrix[5][globalOffset[j]+iglobal-1] = dataTransferData[1];
                  dataOutMatrix[6][globalOffset[j]+iglobal-1] = dataTransferData[2];

                } else {
                  // save Eigen-vector
                  dataOutMatrix[4][globalOffset[j]+iglobal-1] = dataTransferData[3*i+0];
                  dataOutMatrix[5][globalOffset[j]+iglobal-1] = dataTransferData[3*i+1];
                  dataOutMatrix[6][globalOffset[j]+iglobal-1] = dataTransferData[3*i+2];
                }
              }
            } // End dataTransferDiscreteObj loop

            // Remove unused nodes
            numUsedNode = numOutDataPoint;
            AIM_NOTNULL(usedNode, aimInfo, status);

            if (eigenIndex == 0) {
              numUsedConnectivity = numOutDataConnect;
              status = fun3d_removeUnused(aimInfo, numOutVariable, &numUsedNode,
                                          usedNode, &dataOutMatrix,
                                          &numUsedConnectivity, dataConnectMatrix);
              AIM_STATUS(aimInfo, status);
            } else {
              status = fun3d_removeUnused(aimInfo, numOutVariable, &numUsedNode,
                                          usedNode, &dataOutMatrix, NULL, NULL);
              AIM_STATUS(aimInfo, status);
            }

            stringLength = strlen(projectName) +
                           strlen(fileExtBody) +
                           strlen(fileExtMode) +
                           strlen(fileExt) + 5;

            AIM_ALLOC(filename, stringLength+1, char, aimInfo, status);

            sprintf(filename, "%s%s%s%d%s",
                    projectName,
                    fileExtBody,
                    fileExtMode,  // Change modeNumber so it always starts at 1!
                    eigenIndex+1, // eigenVector->eigenValue[eigenIndex].modeNumber,
                    fileExt);

            // Write out eigen-vector in tecplot file
            /*@-nullpass@*/
            status = tecplot_writeFEPOINT(aimInfo,
                                          filename,
                                          "FUN3D Modal",
                                          NULL,
                                          numOutVariable,
                                          (char **)dataOutName,
                                          numUsedNode, //numOutDataPoint,
                                          dataOutMatrix,
                                          dataOutFormat,
                                          numUsedConnectivity, //numOutDataConnect, // numConnectivity
                                          dataConnectMatrix, // connectivity matrix
                                          NULL); // Solution time
            /*@+nullpass@*/
            AIM_STATUS(aimInfo, status);
            AIM_FREE(filename);

          } // End eigenvector names
        } // End if found eigenvectors

        status = CAPS_SUCCESS;

        // Clean-up
    cleanup:

        if (status != CAPS_SUCCESS &&
            status != CAPS_NOTFOUND) printf("Error: Premature exit in fun3d_dataTransfer status = %d\n", status);

        if (dataOutMatrix != NULL) {
          for (i = 0; i < numOutVariable; i++) {
            AIM_FREE(dataOutMatrix[i]);
          }
        }

        AIM_FREE(faces);
        AIM_FREE(dataOutMatrix);
        AIM_FREE(dataConnectMatrix);

        AIM_FREE(filename);
        AIM_FREE(boundName);
        AIM_FREE(usedNode);

        return status;
    }


    // Write FUN3D fun3d.nml file
    int fun3d_writeNML(void *aimInfo, capsValue *aimInputs, cfdBoundaryConditionStruct bcProps)
    {

        int status; // Function return status

        int i; // Indexing

        FILE *fnml = NULL;
        char filename[PATH_MAX];
        char fileExt[] ="fun3d.nml";

        printf("Writing fun3d.nml\n");
        if (aimInputs[Design_Functional-1].nullVal == NotNull ||
            aimInputs[Design_SensFile-1].vals.integer == (int)true) {
    #ifdef WIN32
            snprintf(filename, PATH_MAX, "Flow\\%s", fileExt);
    #else
            snprintf(filename, PATH_MAX, "Flow/%s", fileExt);
    #endif
        } else {
            strcpy(filename, fileExt);
        }

        fnml = aim_fopen(aimInfo, filename, "w");
        if (fnml == NULL) {
            AIM_ERROR(aimInfo, "Unable to open file - %s\n", filename);
            status = CAPS_IOERR;
            goto cleanup;
        }

        // &project
        fprintf(fnml,"&project\n");
        fprintf(fnml," project_rootname = \"%s\"\n",
                aimInputs[Proj_Name-1].vals.string);
        fprintf(fnml,"/\n\n");

        // &raw_grid
        fprintf(fnml,"&raw_grid\n");
        //fprintf(fnml," grid_format = \"%s\"\n",
        //        aimInputs[Mesh_Format-1].vals.string);

    //    if (aimInputs[Mesh_ASCII_Flag-1].vals.integer == (int) true) {
    //        fprintf(fnml," data_format = \"ascii\"\n");
    //    } else fprintf(fnml," data_format = \"stream\"\n");

        fprintf(fnml," grid_format = \"AFLR3\"\n");
        fprintf(fnml," data_format = \"stream\"\n");

        if (aimInputs[Two_Dimensional-1].vals.integer == (int) true) {
            fprintf(fnml," twod_mode = .true.\n");
          //fprintf(fnml," ignore_euler_number = .true.\n");
        }

        fprintf(fnml,"/\n\n");

        // &reference_physical_properties
        fprintf(fnml,"&reference_physical_properties\n");

        if (aimInputs[Mach-1].nullVal != IsNull) {
            fprintf(fnml," mach_number = %f\n", aimInputs[Mach-1].vals.real);
        }

        if (aimInputs[Re-1].nullVal != IsNull) {
            fprintf(fnml," reynolds_number = %f\n", aimInputs[Re-1].vals.real);
        }

        if (aimInputs[Alpha-1].nullVal != IsNull) {
            fprintf(fnml," angle_of_attack = %f\n", aimInputs[Alpha-1].vals.real);
        }

        if (aimInputs[Beta-1].nullVal != IsNull) {
            fprintf(fnml," angle_of_yaw = %f\n", aimInputs[Beta-1].vals.real);
        }

        if (aimInputs[Reference_Temperature-1].nullVal != IsNull) {
                fprintf(fnml," temperature = %f\n", aimInputs[Reference_Temperature-1].vals.real);

                if (aimInputs[Reference_Temperature-1].units != NULL) {
                    fprintf(fnml," temperature_units = \'%s\'\n", aimInputs[Reference_Temperature-1].units);
                }
        }

        fprintf(fnml,"/\n\n");

        // &governing_equations
        fprintf(fnml,"&governing_equations\n");

        if (aimInputs[Viscoux-1].nullVal != IsNull) {
            fprintf(fnml," viscous_terms = \"%s\"\n", aimInputs[Viscoux-1].vals.string);
        }

        if (aimInputs[Equation_Type-1].nullVal != IsNull) {
            fprintf(fnml," eqn_type = \"%s\"\n", aimInputs[Equation_Type-1].vals.string);
        }

        fprintf(fnml,"/\n\n");

        // &nonlinear_solver_parameters
        fprintf(fnml,"&nonlinear_solver_parameters\n");

        if (aimInputs[Time_Accuracy-1].nullVal != IsNull) {
            fprintf(fnml," time_accuracy = \"%s\"\n",
                    aimInputs[Time_Accuracy-1].vals.string);
        }

        if (aimInputs[Time_Step-1].nullVal != IsNull) {
            fprintf(fnml," time_step_nondim = %f\n", aimInputs[Time_Step-1].vals.real);
        }

        if (aimInputs[Num_Subiter-1].nullVal != IsNull) {
            fprintf(fnml," subiterations = %d\n",
                    aimInputs[Num_Subiter-1].vals.integer);
        }

        if (aimInputs[Temporal_Error-1].nullVal != IsNull) {

            fprintf(fnml," temporal_err_control = .true.\n");
            fprintf(fnml," temporal_err_floor = %f\n",
                    aimInputs[Temporal_Error-1].vals.real);

        }

        if (aimInputs[CFL_Schedule-1].nullVal != IsNull) {
            fprintf(fnml," schedule_cfl = %f %f\n",
                    aimInputs[CFL_Schedule-1].vals.reals[0],
                    aimInputs[CFL_Schedule-1].vals.reals[1]);
        }

        if (aimInputs[CFL_Schedule_Iter-1].nullVal != IsNull) {
            fprintf(fnml," schedule_iteration = %d %d\n",
                    aimInputs[CFL_Schedule_Iter-1].vals.integers[0],
                    aimInputs[CFL_Schedule_Iter-1].vals.integers[1]);
        }

        fprintf(fnml,"/\n\n");

        // &code_run_control
        fprintf(fnml,"&code_run_control\n");

        if (aimInputs[Num_Iter-1].nullVal != IsNull) {
            fprintf(fnml," steps = %d\n", aimInputs[Num_Iter-1].vals.integer);
        }

        if (aimInputs[Restart_Read-1].nullVal != IsNull) {
            fprintf(fnml," restart_read = '%s'\n",
                    aimInputs[Restart_Read-1].vals.string);
        }


        fprintf(fnml,"/\n\n");

        //&force_moment_integ_properties
        fprintf(fnml,"&force_moment_integ_properties\n");

        if (aimInputs[Reference_Area-1].nullVal != IsNull) {
            fprintf(fnml," area_reference = %f\n",
                    aimInputs[Reference_Area-1].vals.real);
        }

        if (aimInputs[Moment_Length-1].nullVal != IsNull) {
            fprintf(fnml," x_moment_length = %f\n",
                    aimInputs[Moment_Length-1].vals.reals[0]);

            fprintf(fnml," y_moment_length = %f\n",
                    aimInputs[Moment_Length-1].vals.reals[1]);
        }

        if (aimInputs[Moment_Center-1].nullVal != IsNull) {
            fprintf(fnml," x_moment_center = %f\n",
                    aimInputs[Moment_Center-1].vals.reals[0]);

            fprintf(fnml," y_moment_center = %f\n",
                    aimInputs[Moment_Center-1].vals.reals[1]);

            fprintf(fnml," z_moment_center = %f\n",
                    aimInputs[Moment_Center-1].vals.reals[2]);
        }

        fprintf(fnml,"/\n\n");

        //&boundary_conditions
        fprintf(fnml,"&boundary_conditions\n");

        // Loop through boundary conditions
        for (i = 0; i < bcProps.numSurfaceProp ; i++) {

            // Temperature
            if (bcProps.surfaceProp[i].wallTemperatureFlag == (int) true) {
                fprintf(fnml," wall_temperature(%d) = %f\n",bcProps.surfaceProp[i].bcID,
                        bcProps.surfaceProp[i].wallTemperature);
                fprintf(fnml," wall_temp_flag(%d) = .true.\n",bcProps.surfaceProp[i].bcID);
            }

            // Total pressure and temperature
            if (bcProps.surfaceProp[i].surfaceType == SubsonicInflow) {

                fprintf(fnml, " total_pressure_ratio(%d) = %f\n", bcProps.surfaceProp[i].bcID,
                        bcProps.surfaceProp[i].totalPressure);

                fprintf(fnml, " total_temperature_ratio(%d) = %f\n", bcProps.surfaceProp[i].bcID,
                        bcProps.surfaceProp[i].totalTemperature);
            }

            // Static pressure
            if (bcProps.surfaceProp[i].surfaceType == BackPressure ||
                    bcProps.surfaceProp[i].surfaceType == SubsonicOutflow) {

                fprintf(fnml, " static_pressure_ratio(%d) = %f\n", bcProps.surfaceProp[i].bcID,
                        bcProps.surfaceProp[i].staticPressure);
            }

            // Mach number
            if (bcProps.surfaceProp[i].surfaceType == MachOutflow ||
                    bcProps.surfaceProp[i].surfaceType == MassflowOut) {

                fprintf(fnml, " mach_bc(%d) = %f\n", bcProps.surfaceProp[i].bcID,
                        bcProps.surfaceProp[i].machNumber);
            }

            // Massflow
            if (bcProps.surfaceProp[i].surfaceType == MassflowIn ||
                    bcProps.surfaceProp[i].surfaceType == MassflowOut) {

                fprintf(fnml, " massflow(%d) = %f\n", bcProps.surfaceProp[i].bcID,
                        bcProps.surfaceProp[i].massflow);
            }

            // Fixed inflow and outflow
            /*if (bcProps.surfaceProp[i].surfaceType == FixedInflow ||
                bcProps.surfaceProp[i].surfaceType == FixedOutflow) {

                fprintf(fnml, " qset(%d,1) = %f\n", bcProps.surfaceProp[i].bcID,
                                                    bcProps.surfaceProp[i].staticDensity);

                fprintf(fnml, " qset(%d,2) = %f\n", bcProps.surfaceProp[i].bcID,
                                                    bcProps.surfaceProp[i].uVelocity);

                fprintf(fnml, " qset(%d,3) = %f\n", bcProps.surfaceProp[i].bcID,
                                                    bcProps.surfaceProp[i].vVelocity);

                fprintf(fnml, " qset(%d,4) = %f\n", bcProps.surfaceProp[i].bcID,
                                                    bcProps.surfaceProp[i].wVelocity);

                fprintf(fnml, " qset(%d,5) = %f\n", bcProps.surfaceProp[i].bcID,
                                                    bcProps.surfaceProp[i].staticDensity);
            }*/
        }

        fprintf(fnml,"/\n\n");

        // &noninertial_reference_frame
        fprintf(fnml,"&noninertial_reference_frame\n");


        if (aimInputs[NonInertial_Rotation_Rate-1].nullVal   != IsNull ||
            aimInputs[NonInertial_Rotation_Center-1].nullVal != IsNull) {

            fprintf(fnml," noninertial = .true.\n");
        }

        if (aimInputs[NonInertial_Rotation_Center-1].nullVal != IsNull) {
            fprintf(fnml," rotation_center_x = %f\n",
                    aimInputs[NonInertial_Rotation_Center-1].vals.reals[0]);
            fprintf(fnml," rotation_center_y = %f\n",
                    aimInputs[NonInertial_Rotation_Center-1].vals.reals[1]);
            fprintf(fnml," rotation_center_z = %f\n",
                    aimInputs[NonInertial_Rotation_Center-1].vals.reals[2]);
        }

        if (aimInputs[NonInertial_Rotation_Rate-1].nullVal != IsNull) {
            fprintf(fnml," rotation_rate_x = %f\n",
                    aimInputs[NonInertial_Rotation_Rate-1].vals.reals[0]);
            fprintf(fnml," rotation_rate_y = %f\n",
                    aimInputs[NonInertial_Rotation_Rate-1].vals.reals[1]);
            fprintf(fnml," rotation_rate_z = %f\n",
                    aimInputs[NonInertial_Rotation_Rate-1].vals.reals[2]);

        }

        fprintf(fnml,"/\n\n");

        status = CAPS_SUCCESS;

    cleanup:

        if (status != CAPS_SUCCESS)
            printf("Error: Premature exit in fun3d_writeNML status = %d\n", status);

        if (fnml != NULL) fclose(fnml);

        return status;
    }


    // Write FUN3D movingbody.input file
    int fun3d_writeMovingBody(void *aimInfo, double fun3dVersion, cfdBoundaryConditionStruct bcProps,
                              cfdModalAeroelasticStruct *modalAeroelastic)
    {

        int status; // Function return status

        int i, eigenIndex; // Indexing
        int counter = 0;
        FILE *fp = NULL;
        char *filename = NULL;
        char fileExt[] ="moving_body.input";

        int bodyIndex = 1;
        int stringLength;

        printf("Writing moving_body.input");

        stringLength = strlen(fileExt) + 1;

        AIM_ALLOC(filename,stringLength +1, char, aimInfo, status);

        strcpy(filename, fileExt);
        filename[stringLength] = '\0';

        fp = aim_fopen(aimInfo, filename, "w");
        if (fp == NULL) {
            AIM_ERROR(aimInfo, "Unable to open file - %s\n", filename);
            status = CAPS_IOERR;
            goto cleanup;
        }

        // &body_definitions
        fprintf(fp,"&body_definitions\n");

        fprintf(fp," n_moving_bodies = %d\n", bodyIndex);

        counter = 0;
        for (i = 0; i < bcProps.numSurfaceProp; i++) {

            if (bcProps.surfaceProp[i].surfaceType == Viscous ||
                    bcProps.surfaceProp[i].surfaceType == Inviscid) {

                fprintf(fp," defining_bndry(%d,%d) = %d\n", counter+1,
                        bodyIndex,
                        bcProps.surfaceProp[i].bcID);

                counter += 1;
            }
        }

        fprintf(fp," n_defining_bndry(%d) = %d\n", bodyIndex, counter);

        fprintf(fp," motion_driver(%d) = ", bodyIndex);
        if (modalAeroelastic != NULL) {
            fprintf(fp,"\"aeroelastic\"\n");
        }

        fprintf(fp," mesh_movement(%d) = ", bodyIndex);
        if (modalAeroelastic != NULL) {
            fprintf(fp,"\"deform\"\n");
        }

        fprintf(fp,"/\n\n");

        if (modalAeroelastic != NULL) {

            // &aeroelastic_modal_data
            fprintf(fp,"&aeroelastic_modal_data\n");

            fprintf(fp," nmode(%d) = %d\n", bodyIndex, modalAeroelastic->numEigenValue);

            if (fun3dVersion < 13.1) {
                fprintf(fp," uinf(%d) = %f\n", bodyIndex, modalAeroelastic->freestreamVelocity);
                fprintf(fp," qinf(%d) = %f\n", bodyIndex, modalAeroelastic->freestreamDynamicPressure);
                fprintf(fp," grefl(%d) = %f\n", bodyIndex, modalAeroelastic->lengthScaling);
            } else {
                fprintf(fp," uinf = %f\n", modalAeroelastic->freestreamVelocity);
                fprintf(fp," qinf = %f\n", modalAeroelastic->freestreamDynamicPressure);
                fprintf(fp," grefl = %f\n",modalAeroelastic->lengthScaling);
            }

            fprintf(fp, "\n");


            for (i = 0; i < modalAeroelastic->numEigenValue; i++) {

                eigenIndex = i + 1; // Change mode number so that it always starts at 1
                // modalAeroelastic->eigenValue[i].modeNumber

                fprintf(fp, " ! Mode %d of %d (structural mode %d)\n", eigenIndex,
                        modalAeroelastic->numEigenValue,
                        modalAeroelastic->eigenValue[i].modeNumber);

                fprintf(fp," freq(%d,%d) = %f\n", eigenIndex, bodyIndex, modalAeroelastic->eigenValue[i].frequency);
                fprintf(fp," damp(%d,%d) = %f\n", eigenIndex, bodyIndex, modalAeroelastic->eigenValue[i].damping);

                fprintf(fp," gmass(%d,%d) = %f\n"  , eigenIndex, bodyIndex, modalAeroelastic->eigenValue[i].generalMass);
                fprintf(fp," gdisp0(%d,%d) = %f\n" , eigenIndex, bodyIndex, modalAeroelastic->eigenValue[i].generalDisplacement);
                fprintf(fp," gvel0(%d,%d) = %f\n"  , eigenIndex, bodyIndex, modalAeroelastic->eigenValue[i].generalVelocity);
                fprintf(fp," gforce0(%d,%d) = %f\n", eigenIndex, bodyIndex, modalAeroelastic->eigenValue[i].generalForce);

                fprintf(fp, "\n");
            }
            fprintf(fp,"/\n\n");
        }

        status = CAPS_SUCCESS;

    cleanup:
        if (status != CAPS_SUCCESS)
            printf("Error: Premature exit in fun3d_writeMovingBody status = %d\n",
                   status);

        if (fp != NULL) fclose(fp);

        if (filename != NULL) EG_free(filename);

        return status;
    }


    // Write FUN3D parameterization/sensitivity file
    // Will not calculate shape sensitivities if there are no geometry design variable; will
    // simple check and dump out the body meshes in model.tec files
    int  fun3d_writeParameterization(void *aimInfo,
                                     int numDesignVariable,
                                     cfdDesignVariableStruct designVariable[],
                                     aimMeshRef *meshRef)
    {

        int status; // Function return status

        int i, j, k, m, row, col; // Indexing

        int stringLength = 7;

        // Data transfer Out variables
        char **dataOutName= NULL;

        double ***dataOutMatrix = NULL;
        int *dataOutFormat = NULL;
        int *dataConnectMatrix = NULL;

        int numOutVariable = 4; // x, y, z, id, ... + 3* active GeomIn
        int numOutDataPoint = 0;
        int numOutDataConnect = 0;

        // Variables used in global node mapping
        int ptype, pindex;
        double xyz[3];

        const char *geomInName;
        int numPoint;
        double *dxyz = NULL;

        int index;
        int iface, iglobal;
        int state, nFace;
        ego body, *faces=NULL;

        int alen, ntri, atype, itri, ielem;
        const double *face_xyz, *face_uv, *reals;
        const int *face_ptype, *face_pindex, *face_tris, *face_tric, *nquad=NULL;
        const char *string;

        char message[100];
        char filePre[] = "model.tec.";
        char fileExt[] = ".sd1";
        char *filename = NULL;
        char folder[]  = "Rubberize";
        char zoneTitle[100];

        capsValue *geomInVal;
        int *geomSelect = NULL;

        AIM_ALLOC(geomSelect, numDesignVariable, int, aimInfo, status);

        // Determine number of geometry input variables

        for (i = 0; i < numDesignVariable; i++) {
            geomSelect[i] = (int) false;

            printf("DesignVariable = %s\n", designVariable[i].name);

            index = aim_getIndex(aimInfo, designVariable[i].name, GEOMETRYIN);
            if (index == CAPS_NOTFOUND) continue;
            if (index < CAPS_SUCCESS ) {
              status = index;
              AIM_STATUS(aimInfo, status);
            }

            if(aim_getGeomInType(aimInfo, index) != 0) {
                AIM_ERROR(aimInfo, "GeometryIn value %s is a configuration parameter and not a valid design parameter - can't get sensitivity\n",
                          designVariable[i].name);
                status = CAPS_BADVALUE;
                goto cleanup;
            }


            status = aim_getValue(aimInfo, index, GEOMETRYIN, &geomInVal);
            AIM_STATUS(aimInfo, status);

            numOutVariable += 3*geomInVal->length; // xD1, yD1, zD1, ...

            // Don't compute sensitivities if not needed
            geomSelect[i] = (int) true;
        }

        // No need to write Rubberize files without GeometryIn design variables
        if (numOutVariable == 4) {
            status = CAPS_SUCCESS;
            goto cleanup;
        }

        if (numOutVariable > 99999999) {
            AIM_ERROR(aimInfo, "Array of design variable names will be over-run!");
            status = CAPS_RANGEERR;
            goto cleanup;
        }

        // Allocate our names
        AIM_ALLOC(dataOutName, numOutVariable, char*, aimInfo, status);
        for (i = 0; i < numOutVariable; i++) dataOutName[i] = NULL;

        stringLength = 11;
        j = 1;
        k = 1;
        for (i = 0; i < numOutVariable; i++) {
            AIM_ALLOC(dataOutName[i], stringLength+1, char, aimInfo, status);

            // Set names
            if      (i == 0) sprintf(dataOutName[i], "%s", "x");
            else if (i == 1) sprintf(dataOutName[i], "%s", "y");
            else if (i == 2) sprintf(dataOutName[i], "%s", "z");
            else if (i == 3) sprintf(dataOutName[i], "%s", "id");
            else {

                if      (j == 1) sprintf(dataOutName[i], "%s%d", "xD", k);
                else if (j == 2) sprintf(dataOutName[i], "%s%d", "yD", k);
                else if (j == 3) {
                    sprintf(dataOutName[i], "%s%d", "zD", k);
                    j = 0;
                    k += 1;
                }
                j += 1;
            }
        }

        AIM_ALLOC(dataOutFormat, numOutVariable, int, aimInfo, status);

        // Set data out formatting
        for (i = 0; i < numOutVariable; i++) {
            if (strcasecmp(dataOutName[i], "id") == 0) {
                dataOutFormat[i] = (int) Integer;
            } else {
                dataOutFormat[i] = (int) Double;
            }
        }

        // Allocate data arrays that are going to be output
        AIM_ALLOC(dataOutMatrix, meshRef->nmap, double**, aimInfo, status);
        for (i = 0; i < meshRef->nmap; i++) dataOutMatrix[i] = NULL;

        for (i = 0; i < meshRef->nmap; i++) {
          AIM_ALLOC(dataOutMatrix[i], numOutVariable, double*, aimInfo, status);
          for (j = 0; j < numOutVariable; j++) dataOutMatrix[i][j] = NULL;
        }

        for (i = 0; i < meshRef->nmap; i++) {
          if (meshRef->maps[i].tess == NULL) continue;

          status = EG_statusTessBody(meshRef->maps[i].tess, &body, &state, &numOutDataPoint);
          AIM_STATUS(aimInfo, status);

          // allocate data arrays
          for (j = 0; j < numOutVariable; j++) {
            AIM_ALLOC(dataOutMatrix[i][j], numOutDataPoint, double, aimInfo, status);
          }

          for (iglobal = 0; iglobal < numOutDataPoint; iglobal++) {
            status = EG_getGlobal(meshRef->maps[i].tess,
                                  iglobal+1, &ptype, &pindex, xyz);
            AIM_STATUS(aimInfo, status);

            // First just set the Coordinates
            dataOutMatrix[i][0][iglobal] = xyz[0];
            dataOutMatrix[i][1][iglobal] = xyz[1];
            dataOutMatrix[i][2][iglobal] = xyz[2];

            // Volume mesh node ID
            dataOutMatrix[i][3][iglobal] = meshRef->maps[i].map[iglobal];
          }
        }

        // Loop over the geometry in values and compute sensitivities for all bodies
        m = 4;
        for (j = 0; j < numDesignVariable; j++) {

          if (geomSelect[j] == (int) false) continue;

          geomInName = designVariable[j].name;
          index = aim_getIndex(aimInfo, geomInName, GEOMETRYIN);

          status = aim_getValue(aimInfo, index, GEOMETRYIN, &geomInVal);
          AIM_STATUS(aimInfo, status);

          for (row = 0; row < geomInVal->nrow; row++) {
            for (col = 0; col < geomInVal->ncol; col++) {

              for (i = 0; i < meshRef->nmap; i++) {
                if (meshRef->maps[i].tess == NULL) continue;
                status = aim_tessSensitivity(aimInfo,
                                             geomInName,
                                             row+1, col+1, // row, col
                                             meshRef->maps[i].tess,
                                             &numPoint, &dxyz);
                AIM_STATUS(aimInfo, status, "Sensitivity for: %s\n", geomInName);
                AIM_NOTNULL(dxyz, aimInfo, status);

                for (k = 0; k < numPoint; k++) {
                  dataOutMatrix[i][m+0][k] = dxyz[3*k + 0]; // dx/dGeomIn
                  dataOutMatrix[i][m+1][k] = dxyz[3*k + 1]; // dy/dGeomIn
                  dataOutMatrix[i][m+2][k] = dxyz[3*k + 2]; // dz/dGeomIn
                }
                AIM_FREE(dxyz);
              }
              m += 3;
            }
          }
        }

        // Write sensitivity files for each body tessellation

        for (i = 0; i < meshRef->nmap; i++) {
          if (meshRef->maps[i].tess == NULL) continue;
          status = EG_statusTessBody(meshRef->maps[i].tess, &body, &state, &numOutDataPoint);
          AIM_STATUS(aimInfo, status);

          // check if the tessellation has a mixture of quad and tess
          status = EG_attributeRet(meshRef->maps[i].tess, ".mixed",
                                   &atype, &alen, &nquad, &reals, &string);
          if (status != EGADS_SUCCESS &&
              status != EGADS_NOTFOUND) AIM_STATUS(aimInfo, status);

          status = EG_getBodyTopos(body, NULL, FACE, &nFace, &faces);
          AIM_STATUS(aimInfo, status);

          ielem = 0;
          numOutDataConnect = 0;
          for (iface = 0; iface < nFace; iface++) {
            // get the face tessellation
            status = EG_getTessFace(meshRef->maps[i].tess, iface+1, &alen, &face_xyz, &face_uv,
                                    &face_ptype, &face_pindex, &ntri, &face_tris, &face_tric);
            AIM_STATUS(aimInfo, status);

            if (nquad == NULL) { // all triangles

              // re-allocate data arrays
              AIM_REALL(dataConnectMatrix, 4*(numOutDataConnect + ntri), int, aimInfo, status);

              for (itri = 0; itri < ntri; itri++, ielem++) {
                for (j = 0; j < 3; j++) {
                  status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+j], &iglobal);
                  AIM_STATUS(aimInfo, status);
                  dataConnectMatrix[4*ielem+j] = iglobal;
                }
                // repeat the last node for triangles
                dataConnectMatrix[4*ielem+3] = dataConnectMatrix[4*ielem+2];
              }

              numOutDataConnect += ntri;

            } else { // mixture of tri and quad elements

              // re-allocate data arrays
              AIM_REALL(dataConnectMatrix, 4*(numOutDataConnect + ntri-nquad[iface]), int, aimInfo, status);

              // process triangles
              for (itri = 0; itri < ntri-2*nquad[iface]; itri++, ielem++) {
                for (j = 0; j < 3; j++) {
                  status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+j], &iglobal);
                  AIM_STATUS(aimInfo, status);
                  dataConnectMatrix[4*ielem+j] = iglobal;
                }
                // repeat the last node for triangle
                dataConnectMatrix[4*ielem+3] = dataConnectMatrix[4*ielem+2];
              }
              // process quads
              for (; itri < ntri; itri++, ielem++) {
                for (j = 0; j < 3; j++) {
                  status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+j], &iglobal);
                  AIM_STATUS(aimInfo, status);
                  dataConnectMatrix[4*ielem+j] = iglobal;
                }

                // add the last node from the 2nd triangle to make the quad
                itri++;
                status = EG_localToGlobal(meshRef->maps[i].tess, iface+1, face_tris[3*itri+2], &iglobal);
                AIM_STATUS(aimInfo, status);
                dataConnectMatrix[4*ielem+3] = iglobal;
              }

              numOutDataConnect += ntri-nquad[iface];
            }

          }
          AIM_FREE(faces);

          sprintf(message,"%s %d,", "sensitivity file for body", i+1);

          stringLength = strlen(folder) + 1 + strlen(filePre) + 7 + strlen(fileExt) + 1 ;

          AIM_REALL(filename, stringLength, char, aimInfo, status);

    #ifdef WIN32
          sprintf(filename, "%s\\%s%d%s", folder, filePre, i+1, fileExt);
    #else
          sprintf(filename, "%s/%s%d%s",  folder, filePre, i+1, fileExt);
    #endif

          sprintf(zoneTitle, "%s_%d", "Body", i+1);
          /*@-nullpass@*/
          status = tecplot_writeFEPOINT(aimInfo,
                                        filename,
                                        message,
                                        zoneTitle,
                                        numOutVariable,
                                        dataOutName,
                                        numOutDataPoint,
                                        dataOutMatrix[i],
                                        dataOutFormat,
                                        numOutDataConnect,
                                        dataConnectMatrix,
                                        NULL);
          /*@+nullpass@*/
          AIM_STATUS(aimInfo, status);
        }

        status = CAPS_SUCCESS;

    cleanup:
        (void) string_freeArray(numOutVariable, &dataOutName);
    #ifdef S_SPLINT_S
        EG_free(dataOutName);
    #endif

        if (dataOutMatrix != NULL) {
            for (i = 0; i < meshRef->nmap; i++) {
              if (dataOutMatrix[i] != NULL) {
                  for (j = 0; j < numOutVariable; j++) {
                      AIM_FREE(dataOutMatrix[i][j]);
                  }
              }
              AIM_FREE(dataOutMatrix[i]);
            }
        }

        AIM_FREE(dataOutMatrix);
        AIM_FREE(dataOutFormat);
        AIM_FREE(dataConnectMatrix);
        AIM_FREE(faces);

        AIM_FREE(dxyz);
        AIM_FREE(filename);
        AIM_FREE(geomSelect);

        return status;
    }


    static int _writeFunctinoalComponent(void *aimInfo, FILE *fp, cfdDesignFunctionalCompStruct *comp)
    {
        int status = CAPS_SUCCESS;

        const char *names[] = {"cl", "cd",                   // Lift, drag coefficients
                               "clp", "cdp",                 // Lift, drag coefficients: pressure contributions
                               "clv", "cdv",                 // Lift, drag coefficients: shear contributions
                               "cmx", "cmy", "cmz",          // x/y/z-axis moment coefficients
                               "cmxp", "cmyp", "cmzp",       // x/y/z-axis moment coefficients: pressure contributions
                               "cmxv", "cmyv", "cmzv",       // x/y/z-axis moment coefficients: shear contributions
                               "cx", "cy", "cz",             // x/y/z-axis force coefficients
                               "cxp", "cyp", "czp",          // x/y/z-axis force coefficients: pressure contributions
                               "cxv", "cyv", "czv",          // x/y/z-axis force coefficients: shear contributions
                               "powerx", "powery", "powerz", // x/y/z-axis power coefficients
                               "clcd",                       // Lift-to-drag ratio
                               "fom"    ,                    // Rotorcraft figure of merit
                               "propeff",                    // Rotorcraft propulsive efficiency
                               "rtr"    ,                    // thrust Rotorcraft thrust function
                               "pstag"  ,                    // RMS of stagnation pressure in cutting plane disk
                               "distort",                    // Engine inflow distortion
                               "boom"   ,                    // targ Near-field p/p∞ pressure target
                               "sboom"  ,                    // Coupled sBOOM ground-based noise metrics
                               "ae"     ,                    // Supersonic equivalent area target distribution
                               "press"  ,                    // box RMS of pressure in user-defined box, also pointwise dp/dt, dρ/dt
                               "cpstar" ,                    // Target pressure distributions
                               "sgen"                        // Entropy generation
                              };

        int i, found = (int)false;
        char *function=NULL, *c=NULL;

        for (i = 0; i < sizeof(names)/sizeof(char*); i++)
            if ( strcasecmp(names[i], comp->name) == 0 ) {
                found = (int)true;
                break;
            }

        if (found == (int) false) {
            AIM_ERROR(aimInfo, "Unknown function: '%s'", comp->name);
            AIM_ADDLINE(aimInfo, "Available functions:");
            for (i = 0; i < sizeof(names)/sizeof(char*); i++)
                AIM_ADDLINE(aimInfo, "'%s'", names[i]);
            status = CAPS_BADVALUE;
            goto cleanup;
        }

        // make the name lower case
        AIM_STRDUP(function, comp->name, aimInfo, status);
        for (c = function; *c != '\0'; ++c) *c = tolower(*c);

        // fprintf(fp, "Components of function   1: boundary id (0=all)/name/value/weight/target/power\n");
        fprintf(fp, " %d %s          %f %f %f %f\n", comp->bcID,
                                                     function,
                                                     0.0,
                                                     comp->weight,
                                                     comp->target,
                                                     comp->power);

        status = CAPS_SUCCESS;

    cleanup:
        AIM_FREE(function);
        return status;
    }


    // Write FUN3D  rubber.data file
    // Will not write shape entries unless explicitly told to check if they are need
    int fun3d_writeRubber(void *aimInfo,
                          cfdDesignStruct design,
                          int checkGeomShape,
                          double fun3dVersion,
                          aimMeshRef *meshRef)
    {
        int status; // Function return status

        int i, j, k, m; // Indexing

        int numBody = 0, numShapeVar = 0;

        char file[] = "rubber.data";
        FILE *fp = NULL;

        printf("Writing %s \n", file);
        if (meshRef == NULL) return CAPS_NULLVALUE;

        // Open file
        fp = aim_fopen(aimInfo, file, "w");
        if (fp == NULL) {
            AIM_ERROR(aimInfo, "Unable to open file: %s\n", file);
            status = CAPS_IOERR;
            goto cleanup;
        }

        numBody = meshRef->nmap;

        if (checkGeomShape == (int) true) {
            // Determine number of geometry input variables
            for (i = 0; i < design.numDesignVariable; i++) {

                if (design.designVariable[i].type != DesignVariableGeometry) continue;

                numShapeVar += design.designVariable[i].var->length; // xD1, yD1, zD1, ...
            }
        }

        // Don't write out body information if there are no geometry design variables
        if (numShapeVar == 0) numBody = 0;


        fprintf(fp, "################################################################################\n");
        fprintf(fp, "########################### Design Variable Information ########################\n");
        fprintf(fp, "################################################################################\n");
        fprintf(fp, "Global design variables (Mach number, AOA, Yaw, Noninertial rates)\n");
        fprintf(fp, "Var Active         Value               Lower Bound            Upper Bound\n");

        for (i = 0; i < design.numDesignVariable; i++) {

            if (strcasecmp(design.designVariable[i].name, "Mach") != 0) continue;

            if (design.designVariable[i].var->length < 1) {
                status = CAPS_RANGEERR;
                goto cleanup;
            }

            fprintf(fp, "Mach    1   %.15E  %.15E  %.15E\n", design.designVariable[i].value[0],
                                                             design.designVariable[i].lowerBound[0],
                                                             design.designVariable[i].upperBound[0]);
            break;
        }

        if (i >= design.numDesignVariable) fprintf(fp, "Mach    0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");

        for (i = 0; i < design.numDesignVariable; i++) {

            if (strcasecmp(design.designVariable[i].name, "Alpha") != 0) continue;

            if (design.designVariable[i].var->length < 1) {
                status = CAPS_RANGEERR;
                goto cleanup;
            }

            fprintf(fp, "AOA     1   %.15E  %.15E  %.15E\n", design.designVariable[i].value[0],
                                                             design.designVariable[i].lowerBound[0],
                                                             design.designVariable[i].upperBound[0]);
            break;
        }

        if (i >= design.numDesignVariable) fprintf(fp, "AOA     0   0.000000000000000E+00  0.000000000000000E+00  0.00000000000000E+00\n");


        if (fun3dVersion > 12.4) {
            // FUN3D version 13.1 - version 12.4 doesn't have these available

            for (i = 0; i < design.numDesignVariable; i++) {

                if (strcasecmp(design.designVariable[i].name, "Beta") != 0) continue;

                if (design.designVariable[i].var->length < 1) {
                    status = CAPS_RANGEERR;
                    goto cleanup;
                }

                fprintf(fp, "Yaw     1   %.15E  %.15E  %.15E\n", design.designVariable[i].value[0],
                                                                 design.designVariable[i].lowerBound[0],
                                                                 design.designVariable[i].upperBound[0]);
                break;
            }

            if (i >= design.numDesignVariable) fprintf(fp, "Yaw     0   0.000000000000000E+00  0.000000000000000E+00  0.00000000000000E+00\n");

            for (i = 0; i < design.numDesignVariable; i++) {

                if (strcasecmp(design.designVariable[i].name, "NonInertial_Rotation_Rate") != 0) continue;

                if (design.designVariable[i].var->length < 3) {
                    status = CAPS_RANGEERR;
                    goto cleanup;
                }

                fprintf(fp, "xrate   1   %.15E  %.15E  %.15E\n", design.designVariable[i].value[0],
                                                                 design.designVariable[i].lowerBound[0],
                                                                 design.designVariable[i].upperBound[0]);
                break;
            }

            if (i >= design.numDesignVariable) fprintf(fp, "xrate   0   0.000000000000000E+00  0.000000000000000E+00  0.00000000000000E+00\n");

            for (i = 0; i < design.numDesignVariable; i++) {

                if (strcasecmp(design.designVariable[i].name, "NonInertial_Rotation_Rate") != 0) continue;

                if (design.designVariable[i].var->length < 3) {
                    status = CAPS_RANGEERR;
                    goto cleanup;
                }

                fprintf(fp, "yrate   1   %.15E  %.15E  %.15E\n", design.designVariable[i].value[1],
                                                                 design.designVariable[i].lowerBound[1],
                                                                 design.designVariable[i].upperBound[1]);
                break;
            }

            if (i >= design.numDesignVariable) fprintf(fp, "yrate   0   0.000000000000000E+00  0.000000000000000E+00  0.00000000000000E+00\n");

            for (i = 0; i < design.numDesignVariable; i++) {

                if (strcasecmp(design.designVariable[i].name, "NonInertial_Rotation_Rate") != 0) continue;

                if (design.designVariable[i].var->length < 3) {
                    status = CAPS_RANGEERR;
                    goto cleanup;
                }

                fprintf(fp, "zrate   1   %.15E  %.15E  %.15E\n", design.designVariable[i].value[2],
                                                                 design.designVariable[i].lowerBound[2],
                                                                 design.designVariable[i].upperBound[2]);
                break;
            }

            if (i >= design.numDesignVariable) fprintf(fp, "zrate   0   0.000000000000000E+00  0.000000000000000E+00  0.00000000000000E+00\n");
        }

        fprintf(fp, "Number of bodies\n");
        fprintf(fp, "%d\n", numBody);
        for (i = 0; i < numBody; i++) {
            fprintf(fp, "Rigid motion design variables for 'Body %d'\n", i+1);
            fprintf(fp, "Var Active         Value               Lower Bound            Upper Bound\n");
            fprintf(fp, "RotRate  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotFreq  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotAmpl  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotOrgx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotOrgy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotOrgz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotVecx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotVecy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "RotVecz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "TrnRate  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "TrnFreq  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "TrnAmpl  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "TrnVecx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "TrnVecy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            fprintf(fp, "TrnVecz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00\n");
            if (fun3dVersion > 12.4) {
                // FUN3D version 13.1 - version 12.4 doesn't have option 5
                fprintf(fp, "Parameterization Scheme (Massoud=1 Bandaids=2 Sculptor=4 User-Defined=5)\n");
                fprintf(fp, "5\n");
            } else {

                fprintf(fp, "Parameterization Scheme (Massoud=1 Bandaids=2 Sculptor=4)\n");
                fprintf(fp, "1\n");
            }

            fprintf(fp, "Number of shape variables for 'Body %d'\n", i+1);
            fprintf(fp, "%d\n", numShapeVar);
            fprintf(fp, "Index Active         Value               Lower Bound            Upper Bound\n");

            m = 1;
            for (j = 0; j < design.numDesignVariable; j++) {

                if (design.designVariable[j].type != DesignVariableGeometry) continue;

                for (k = 0; k < design.designVariable[j].var->length; k++ ) {

                    fprintf(fp, "%d    1   %.15E  %.15E  %.15E\n", m, design.designVariable[j].value[k],
                                                                      design.designVariable[j].lowerBound[k],
                                                                      design.designVariable[j].upperBound[k]);

                    m += 1;
                }
            }
        }

        fprintf(fp, "################################################################################\n");
        fprintf(fp, "############################### Function Information ###########################\n");
        fprintf(fp, "################################################################################\n");
        fprintf(fp, "Number of composite functions for design problem statement\n");
        fprintf(fp, "%d\n", design.numDesignFunctional);

        for (i = 0; i < design.numDesignFunctional; i++) {
            fprintf(fp, "################################################################################\n");
            fprintf(fp, "Cost function (1) or constraint (2)\n");
            fprintf(fp, "1\n");
            fprintf(fp, "If constraint, lower and upper bounds\n");
            fprintf(fp, "0.0 0.0\n");
            fprintf(fp, "Number of components for function   %d\n", i+1);
            fprintf(fp, "%d\n", design.designFunctional[i].numComponent);
            fprintf(fp, "Physical timestep interval where function is defined\n");
            fprintf(fp, "1 1\n");
            fprintf(fp, "Composite function weight, target, and power\n");
            fprintf(fp, "1.0 0.0 1.0\n");
            fprintf(fp, "Components of function   %d: boundary id (0=all)/name/value/weight/target/power\n", i+1);

            for (j = 0; j < design.designFunctional[i].numComponent; j++) {
                //fprintf(fp, "0 clcd          0.000000000000000    1.000   10.00000 2.000\n");
                status = _writeFunctinoalComponent(aimInfo, fp, &design.designFunctional[i].component[j]);
                if (status != CAPS_SUCCESS) goto cleanup;
            }

            fprintf(fp, "Current value of function   %d\n", i+1);
            fprintf(fp, "0.000000000000000\n");
            fprintf(fp, "Current derivatives of function wrt global design variables\n");
            fprintf(fp, "0.000000000000000\n");
            fprintf(fp, "0.000000000000000\n");

            if (fun3dVersion > 12.4) {
                // FUN3D version 13.1 - version 12.4 doesn't have these available
                fprintf(fp, "0.000000000000000\n"); // Yaw
                fprintf(fp, "0.000000000000000\n"); // xrate
                fprintf(fp, "0.000000000000000\n"); // yrate
                fprintf(fp, "0.000000000000000\n"); // zrate
            }

            for (j = 0; j < numBody; j++) {
                fprintf(fp, "Current derivatives of function wrt rigid motion design variables of body %d\n", j+1);
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "0.000000000000000\n");
                fprintf(fp, "Current derivatives of function wrt shape design variables of body %d\n", j+1);

                for (k = 0; k < design.numDesignVariable; k++) {

                    if (design.designVariable[k].type != DesignVariableGeometry) continue;

                    for (m = 0; m < design.designVariable[k].var->length; m++ ) fprintf(fp, "0.000000000000000\n");
                }
            }
        }

        status = CAPS_SUCCESS;

    cleanup:
        if (status != CAPS_SUCCESS)
            printf("Error: Premature exit in fun3d_writeRubber status = %d\n",
                   status);

        if (fp != NULL) fclose(fp);

        return status;

        /* Version 13.1 - template
    ################################################################################
    ########################### Design Variable Information ########################
    ################################################################################
    Global design variables (Mach number, AOA, Yaw, Noninertial rates)
    Var Active         Value               Lower Bound            Upper Bound
    Mach    0   0.800000000000000E+00  0.000000000000000E+00  0.900000000000000E+00
      AOA    1   1.000000000000000E+00  0.000000000000000E+00  5.000000000000000E+00
      Yaw    0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    xrate    0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    yrate    0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    zrate    0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    Number of bodies
    2
    Rigid motion design variables for 'wing'
    Var Active         Value               Lower Bound            Upper Bound
    RotRate  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotFreq  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotAmpl  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotOrgx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotOrgy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotOrgz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotVecx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotVecy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotVecz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnRate  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnFreq  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnAmpl  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnVecx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnVecy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnVecz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    Parameterization Scheme (Massoud=1 Bandaids=2 Sculptor=4 User-Defined=5)
    1
    Number of shape variables for 'wing'
    3
    Index Active         Value               Lower Bound            Upper Bound
    1    1   1.000000000000000E+00  0.000000000000000E+00  2.000000000000000E+00
    2    1   1.000000000000000E+00  0.000000000000000E+00  2.000000000000000E+00
    3    1   1.000000000000000E+00  0.000000000000000E+00  2.000000000000000E+00
    Rigid motion design variables for 'tail'
    Var Active         Value               Lower Bound            Upper Bound
    RotRate  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotFreq  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotAmpl  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotOrgx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotOrgy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotOrgz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotVecx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotVecy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    RotVecz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnRate  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnFreq  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnAmpl  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnVecx  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnVecy  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    TrnVecz  0   0.000000000000000E+00  0.000000000000000E+00  0.000000000000000E+00
    Parameterization Scheme (Massoud=1 Bandaids=2 Sculptor=4 User-Defined=5)
    2
    Number of shape variables for 'tail'
    2
    Index Active         Value               Lower Bound            Upper Bound
    1    1   2.000000000000000E+00 -1.000000000000000E+00  5.000000000000000E+00
    2    1   2.000000000000000E+00 -1.000000000000000E+00  5.000000000000000E+00
    ################################################################################
    ############################### Function Information ###########################
    ################################################################################
    Number of composite functions for design problem statement
    2
    ################################################################################
    Cost function (1) or constraint (2)
    1
    If constraint, lower and upper bounds
    0.0 0.0
    Number of components for function   1
    1
    Physical timestep interval where function is defined
    1 1
    Composite function weight, target, and power
    1.0 0.0 1.0
    Components of function   1: boundary id (0=all)/name/value/weight/target/power
    0 cl            0.000000000000000    1.000   10.00000 2.000
    Current value of function   1
    0.000000000000000
    Current derivatives of function wrt global design variables
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt rigid motion design variables of body   1
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt shape design variables of body   1
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt rigid motion design variables of body   2
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt shape design variables of body   2
    0.000000000000000
    0.000000000000000
    ################################################################################
    Cost function (1) or constraint (2)
    2
    If constraint, lower and upper bounds
    -0.03 -0.01
    Number of components for function   2
    1
    Physical timestep interval where function is defined
    1 1
    Composite function weight, target, and power
    1.0 0.0 1.0
    Components of function   2: boundary id (0=all)/name/value/weight/target/power
    0 cmy           0.000000000000000    1.000    0.00000 1.000
    Current value of function   2
    0.000000000000000
    Current derivatives of function wrt global design variables
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt rigid motion design variables of body   1
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt shape design variables of body   1
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt rigid motion design variables of body   2
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    0.000000000000000
    Current derivatives of function wrt shape design variables of body   2
    0.000000000000000
    0.000000000000000
         */
    }

    // Finds a line in rubber.data that matches header
    static int findHeader(const char *header, char **line, size_t *nline, int *iline, FILE *fp)
    {
        int i;
        while (getline(line, nline, fp) != -1) {
            (*iline)++;
            if (nline == 0) continue;
            if ((*line)[0] == '#') continue;
            i = 0;
            while ((*line)[i] == ' ' && (*line)[i] != '\0') i++;
            if (strncasecmp(header, &(*line)[i], strlen(header)) == 0)
              break;
        }
        if (feof(fp)) return CAPS_IOERR;

        return CAPS_SUCCESS;
    }


    // Read objective value and derivatives from FUN3D rubber.data file
    // Will not read shape entries unless explicitly told to check if they are needed
    int fun3d_readRubber(void *aimInfo,
                         cfdDesignStruct design,
                         int checkGeomShape,
                         double fun3dVersion,
                         aimMeshRef *meshRef)
    {
        int status; // Function return status

        int i, j, k, ibody; // Indexing

        int numShapeVar = 0;

        size_t nline;
        int iline=0;
        char *line=NULL;
        char file[] = "rubber.data";
        double dfun_dvar = 0;
        FILE *fp = NULL;

        int numBody;

        // Get AIM bodies
        numBody = meshRef->nmap;

        printf("Reading %s \n", file);

        // Open file
        fp = aim_fopen(aimInfo, file, "r");
        if (fp == NULL) {
            AIM_ERROR(aimInfo, "Unable to open file: %s\n", file);
            status = CAPS_IOERR;
            goto cleanup;
        }

        for (i = 0; i < design.numDesignFunctional; i++) {

            status = findHeader("Current value of function", &line, &nline, &iline, fp);
            AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);

            // Get the line with the objective value
            status = getline(&line, &nline, fp); iline++;
            if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
            AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
            AIM_NOTNULL(line, aimInfo, status);

            status = sscanf(line, "%lf", &design.designFunctional[i].value);
            if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
            AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);

            // skip: Current derivatives of function wrt rigid motion design variables of
            status = getline(&line, &nline, fp); iline++;
            if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
            AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
            AIM_NOTNULL(line, aimInfo, status);

            // read the dFun/dMach
            status = getline(&line, &nline, fp); iline++;
            if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
            AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
            AIM_NOTNULL(line, aimInfo, status);

            for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {

                if (strcasecmp(design.designFunctional[i].dvar[j].name, "Mach") != 0) continue;

                status = sscanf(line, "%lf", &design.designFunctional[i].dvar[j].value[0]);
                if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                break;
            }

            // read the dFun/dAOA
            status = getline(&line, &nline, fp); iline++;
            if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
            AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
            AIM_NOTNULL(line, aimInfo, status);

            for (j = 0; j < design.numDesignVariable; j++) {

                if (strcasecmp(design.designFunctional[i].dvar[j].name, "Alpha") != 0) continue;

                status = sscanf(line, "%lf", &design.designFunctional[i].dvar[j].value[0]);
                if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                break;
            }

            if (fun3dVersion > 12.4) {
                // FUN3D version 13.1 - version 12.4 doesn't have these available

                // read the dFun/dBeta
                status = getline(&line, &nline, fp); iline++;
                if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                AIM_NOTNULL(line, aimInfo, status);

                for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {

                    if (strcasecmp(design.designFunctional[i].dvar[j].name, "Beta") != 0) continue;

                    status = sscanf(line, "%lf", &design.designFunctional[i].dvar[j].value[0]);
                    if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                    AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                    break;
                }

                // read the dFun/dNonInertial_Rotation_Rate[0]
                status = getline(&line, &nline, fp); iline++;
                if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                AIM_NOTNULL(line, aimInfo, status);

                for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {

                    if (strcasecmp(design.designFunctional[i].dvar[j].name, "NonInertial_Rotation_Rate") != 0) continue;

                    status = sscanf(line, "%lf", &design.designFunctional[i].dvar[j].value[0]);
                    if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                    AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                    break;
                }

                // read the dFun/dNonInertial_Rotation_Rate[1]
                status = getline(&line, &nline, fp); iline++;
                if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                AIM_NOTNULL(line, aimInfo, status);

                for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {

                    if (strcasecmp(design.designFunctional[i].dvar[j].name, "NonInertial_Rotation_Rate") != 0) continue;

                    status = sscanf(line, "%lf", &design.designFunctional[i].dvar[j].value[1]);
                    if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                    AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                    break;
                }

                // read the dFun/dNonInertial_Rotation_Rate[2]
                status = getline(&line, &nline, fp); iline++;
                if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                AIM_NOTNULL(line, aimInfo, status);

                for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {

                    if (strcasecmp(design.designFunctional[i].dvar[j].name, "NonInertial_Rotation_Rate") != 0) continue;

                    status = sscanf(line, "%lf", &design.designFunctional[i].dvar[j].value[2]);
                    if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                    AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                    break;
                }
            }


            numShapeVar = 0; // Need to re-zero every functional loop

            if (checkGeomShape == (int) true) {
                // zero out previous derivatives
                for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {
                    if (design.designFunctional[i].dvar[j].type != DesignVariableGeometry) continue;
                    numShapeVar++;
                    for (k = 0; k < design.designVariable[j].var->length; k++ ) {
                      design.designFunctional[i].dvar[j].value[k] = 0;
                    }
                }
            }

            // No body information if there are no Geometry derivatives
            if (numShapeVar == 0) numBody = 0;

            for (ibody = 0; ibody < numBody; ibody++) {

              // Rigid motion design variables
              status = findHeader("Current derivatives of", &line, &nline, &iline, fp);
              AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);

              // Skip reading rigid motion design variables for now
             
              // Read shape design variables
              status = findHeader("Current derivatives of", &line, &nline, &iline, fp);
              AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);

              for (j = 0; j < design.designFunctional[i].numDesignVariable; j++) {

                  if (design.designFunctional[i].dvar[j].type != DesignVariableGeometry) continue;

                  for (k = 0; k < design.designVariable[j].var->length; k++ ) {

                      // read the dFun/dDesignVar[k]
                      status = getline(&line, &nline, fp); iline++;
                      if (status == -1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                      AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);
                      AIM_NOTNULL(line, aimInfo, status);

                      status = sscanf(line, "%lf", &dfun_dvar);
                      if (status != 1) status = CAPS_IOERR; else status = CAPS_SUCCESS;
                      AIM_STATUS(aimInfo, status, "rubber.data line %d", iline);

                      // accumulate derivatives across bodies
                      design.designFunctional[i].dvar[j].value[k] += dfun_dvar;
                  }
              }
            }
        }

        status = CAPS_SUCCESS;

    cleanup:

        if (line != NULL) free(line); // Must use free!
        if (fp   != NULL) fclose(fp);

        return status;
    }

    // Make FUN3D directory structure/tree
    int fun3d_makeDirectory(void *aimInfo)
    {
        int status; // Function return status

        char filename[PATH_MAX];

        char flow[] = "Flow";
        char datafile[] = "datafiles";
        char adjoint[] = "Adjoint";
        char rubber[] = "Rubberize";

        printf("Creating FUN3D directory tree\n");

        // Flow
        status = aim_mkDir(aimInfo, flow);
        AIM_STATUS(aimInfo, status);

        // Datafiles
        sprintf(filename, "%s/%s", flow, datafile);
        status = aim_mkDir(aimInfo, filename);
        AIM_STATUS(aimInfo, status);

        // Adjoint
        status = aim_mkDir(aimInfo, adjoint);
        AIM_STATUS(aimInfo, status);

        // Rubber
        status = aim_mkDir(aimInfo, rubber);
        AIM_STATUS(aimInfo, status);

        status = CAPS_SUCCESS;

    cleanup:
        return status;
    }



    // Morphing input
    // First time through and morphing
    // -  Write bodies and mesh to disc only if mesh is linked a
    // -  AIM_CP_FIle the meshfile
    //


    // aim_storeMeshRef(aimInfo, meshRef, MESHEXTENSION);
    //aim_storeMeshRef(aimInfo, meshRef, MESHEXTENSION);
    //
    //aimMeshRef meshRef2;
    //aim_initMeshRef(&meshRef2);
    //aim_loadMeshRef(aimInfo, &meshRef2);
    //aim_freeMeshRef(&meshRef2);

    // Logic for selecting/setting mesh pointer if morphing the mesh
    int fun3d_morphMeshLogic(void *aimInfo, int storeAllowed, aimMeshRef **meshRef, aimMeshRef *meshRefObj)
    {
        int status = CAPS_SUCCESS;

        AIM_NOTNULL(meshRefObj, aimInfo, status);

        if (*meshRef != NULL && storeAllowed == (int) true) { // If we are NOT null lets store the mesh - if allowed

            status = aim_storeMeshRef(aimInfo, *meshRef, MESHEXTENSION);
            AIM_STATUS(aimInfo, status);

            *meshRef =  meshRefObj;

           // Lets "reload" the meshRef now - A little awkward but.....
           status = aim_loadMeshRef(aimInfo, *meshRef);
           AIM_STATUS(aimInfo, status);

        } else if (*meshRef != NULL  && storeAllowed == (int) false) { // If we are NOT null

             // Do nothing

        } else { // *meshRef == NULL

            *meshRef =  meshRefObj;

            // Lets "load" the meshRef now
            status = aim_loadMeshRef(aimInfo, *meshRef);
            AIM_STATUS(aimInfo, status);
        }

        cleanup:
            return status;
    }


    //{
    //    int status = CAPS_SUCCESS;
    //
    //    AIM_NOTNULL(meshRefObj, aimInfo, status);
    //
    //    if (*meshRef != NULL && storeAllowed == (int) true) { // If we are NOT null lets store the mesh
    //        status = aim_storeMeshRef(aimInfo, *meshRef, MESHEXTENSION);
    //        AIM_STATUS(aimInfo, status);
    //
    //        meshRef = NULL;
    //    }
    //
    //    *meshRef =  meshRefObj;
    //
    //    // Lets "reload" the meshRef now - A little awkward but.....
    //    status = aim_loadMeshRef(aimInfo, *meshRef);
    //    AIM_STATUS(aimInfo, status);
    //
    //    cleanup:
    //        return status;
    //}

    // Map the old surface tessellation on to the new bodies
    int fun3d_morpMeshUpdate(void *aimInfo,  aimMeshRef *meshRef, int numBody, ego *bodies)
    {
        int status = CAPS_SUCCESS;
        int i=0;
        int state, numVert;
        ego bodyMapping;
        ego body;
        ego tess;

        // Have the number of bodies changed?
        if (meshRef->nmap != numBody) {
            printf("The number of original surface meshes does NOT equal the number of current bodies!\n");
            AIM_STATUS(aimInfo, CAPS_MISMATCH);
        }

        // Are the bodies topological equivalent?
        for (i = 0; i < meshRef->nmap; i++) {

            status = EG_statusTessBody(meshRef->maps[i].tess, &body, &state, &numVert);
            AIM_STATUS(aimInfo, status);

            status = EG_mapBody(body, bodies[i], "_faceID",  &bodyMapping); // "_faceID" - same as in OpenCSM
            if (status != EGADS_SUCCESS || bodyMapping != NULL) {

                printf("New and old body %d (of %d) do not appear to be topologically equivalent!\n", i+1, meshRef->nmap);

                if (bodyMapping != NULL) {
                    printf("Body mapping isn't NULL!\n");
                }

                AIM_STATUS(aimInfo, CAPS_MISMATCH);
            }
        }

        // Now lets "tweak" the surface tessellation - map the old tessellation to the new bodies
        for (i = 0; i < meshRef->nmap; i++) {

            status = EG_copyObject(bodies[i], NULL, &body);
            AIM_STATUS(aimInfo, status);

            status = EG_mapTessBody(meshRef->maps[i].tess,
                                    body,
                                    &tess);
            AIM_STATUS(aimInfo, status);

            status = EG_deleteObject(meshRef->maps[i].tess);
            meshRef->maps[i].tess = tess;

        }

        cleanup:
            return status;
    }
    ryan / detail
  50. Remove old egads file in aim_storeMeshRef. Set AIMptr to NULL when unlinking. — galbramc / detail
  51. clarify description of SELECT x -1 ibody1 — jfdannen / detail
  52. update to account for latest EGADS fix to EG_generalBoolean — jfdannen / detail
  53. add ocsmRegBcstCB to ocsm.def — jfdannen / detail
  54. update Building button to show progress of build in ESP; fix memory leak when ELEVATE command fails (like it often does in the combine.udc); extend SELECT command to SELECT all Faces/Edges/Nodes in current Body that match a Face in another Body; add SELECT NOT to SELECT the Faces/Edges/Nodes not selected and vice versa; fix bug associated with determining if an Edge is a subset of another; update to account for change in EG_isEquivalent; fix bug that did not copy attributes from an Edge in a WireBody that was INTERSECTed with a SolidBody to the new Edge; add PRINT_LAST_EGO compile-time flag to print the last ego after every step in an ocsmBuild; fix bug in sensCSM when trying to remove .csm or .cpc extension from the casename when it did not exist; extend SELECT command to SELECT all Faces/Edges/Nodes in current Body that are within another Body — jfdannen / detail
  55. fix DUMP x.sens for degenerate Edges; add combine.udc so that old .csm scripts that used the (now deprecated) COMBINE command still work; add combine* test cases; add makeErep journal entry so that ereped can be tested; modify at-itype, at-nface, and at-nedge if there is an erep; add POWLE and POWTE arguments to udfDroop; add new droop* test cases; add udfNaca6mc to warp the input thickness distribution with the sum of multiple NACA 6-series meanlines; add naca6mc* test cases — jfdannen / detail
  56. protect against string overflows in strncpy and strncat; fix mesgCallbackFromOpenCSM so that it does not try to broadcast text when in batch mode; initial version of udpNaca6mc — jfdannen / detail
  57. Remove dependencies from file copies — haimes / detail
  58. clean up usage of include files; update dependencies in Makefile and NMakefile — jfdannen / detail
  59. remove pyscript from lint in serveESP.make — jfdannen / detail
  60. update serveCSM.make to fix stanilizer error for pyscript — jfdannen / detail
  61. another attempt to move building of pyscript from Makefile to serveESP.make — jfdannen / detail
  62. move building of pyscript from Makefile to serveESP.make — jfdannen / detail
  63. fix recently added bug in ereped that only allowed 9 colors; remove timHold from viewBodys.py; add batch flag to ESP structure; add assert command in browserToServer; add method of verifying ereped and plugs if running from journal and in -batch mode; next versions of udfDroop2 and udfDroop3; migrate testing in Makefile.DARWIN64 and Makefile.LINUX64 from serveCSM to serveESP; fix bug in esp.SetCaps() in pyESP — jfdannen / detail
  64. next version of udfDroop2; first version of udfDroop3 — jfdannen / detail
  65. next (still incomplete) version of udfDroop2 — jfdannen / detail
  66. initial version of udfDroop2 — jfdannen / detail
  67. fix test_pyOCSM to account for updated MESSAGE statement — jfdannen / detail
  68. extend MESSAGE to optionally write to a file; modify message test case; update ESP-help and ESP_QuickReference — jfdannen / detail
  69. fix memory leak when a UDF returns an error; remove extra prints when udfFlend or udfOffset detect an error; update sanitize targets in Makefile.LINUX — jfdannen / detail
  70. allow OFFSET to function properly when the number of Edges in the offset is fewer than the original Body; fix escape-close-parenthesis in ESP_QuickReference; add ability to create periodic SPLINE in sketcher by using SSLOPE(0); add sslope6* test cases — jfdannen / detail
  71. add assert in udfOffset to eliminate warnings on gcc — jfdannen / detail
  72. fix bug that caused ereped to not work for a named Body; fix bug that added bar at end of file that was being editted in ESP; extend ereped so that it can be applied if there are multiple Bodys on the stack; add ereped8 test case; fix ESP hint associated with ELEVATE command; fix bug when SELECT EGDE with a bounding box was applied to a Body with degenerate Edges; add extractBodys test case; fix array bounds error in udpEqn2body; fix bug in ereped initializations for a single Body — jfdannen / detail
  73. remove use of _scaleuv Attribute — jfdannen / detail
  74. allow very long message to be sent from browser to server; add setCsmFile instead of setScmFileBeg/Mid/End; if error occurs when processing a timMesg, put the tim back into READY mode; post message when erep is successfully generated; implement udpEqn2body for SheetBodys; update frustrum3 test case; use __usedBodys__ attribute when computing velocity of Faces or Edges for RULE and BLEND; fix bug in sensCSM that did not reset maximum errors for Bodys when in -tess mode; fix big that did not copy .hasdots during RESTORE . (dot) — jfdannen / detail
  75. Fix the new isEquivalent for periodic curves split into 2 Edges — haimes / detail
  76. modified Ints to Int32 and added egadslite tests — docampo / detail
  77. recompiled pdf references were with ?? — docampo / detail
  78. removed EL flag from some of the effectiveTopology functions — docampo / detail
  79. fixed typos — docampo / detail
  80. Remove bug that would error out if there were no Faces during generalBoolean operations — haimes / detail
  81. Update isEquivalent to fix previous problem — haimes / detail
  82. Allow for senses to be flipped when applying EG_isEquivalent — haimes / detail
  83. added the ego. wrap to the getfield operation — docampo / detail
  84. update udpTire for new include scheme — jfdannen / detail
  85. Fix Edge mapping problem introduced since Rev 1.21 — haimes / detail
  86. changed .obj -> .ego — docampo / detail
  87. Add TOML to egadslite dep — galbramc / detail
  88. compiling for Julia 1.6 and 1.8. test fails for 1.8 — docampo / detail
  89. Update makeEnv to reflect newer MAC OS revs — haimes / detail
  90. Add the Julia interface to the EGADS API documentation — haimes / detail
  91. Try to fix stanalyzer errors again — haimes / detail
  92. Fix jlEGADS makefiles — galbramc / detail
  93. Try to fix stanalyzer errors — haimes / detail
  94. Suppress gcc-12 warning — galbramc / detail
  95. Effective Topology: apply last change only for EFaces with more than 1 Face — haimes / detail
  96. Effective Topology: check result of getEdgeUV against invEval and pick the closer — haimes / detail
  97. A different possible fix for the MemcheckOcsm on the rule28 cases — haimes / detail
  98. A different possible fix for the MemcheckOcsm on the rule28 cases — haimes / detail
  99. A possible fix for the MemcheckOcsm on the rule28 cases — haimes / detail
  100. Effective Topology: Mark Planar/Periodic EFaces not to tessellate Edges based on Face Curvature — haimes / detail
  101. Fix scan-build warning from last commit again — haimes / detail
  102. Fix scan-build warning from last commit — haimes / detail
  103. Effective Topology: Fix NM Sheetbody Node removal — haimes / detail
  104. Fix NULL bays at end with multiNode Rule — haimes / detail
  105. Updated ruled sensitvities for multiNode — galbramc / detail
  106. A minor update of the documentation of EG_approximate — haimes / detail
  107. Update the docs to specify the additions to EG_approximate and EG_ruled — haimes / detail
  108. Suppress scipy memory leak — galbramc / detail
  109. Another python valgrind suppression — galbramc / detail
  110. Add Ubuntu 22.04 valgrind suppressions — galbramc / detail
  111. Use system valgrind — galbramc / detail
  112. Small cleanup of email template — galbramc / detail
  113. Remove torch for now — galbramc / detail
  114. Log parser fixes — galbramc / detail
  115. Suppress torch memory leaks — galbramc / detail
  116. Upgrade sanitizer path to 14.0.0 — galbramc / detail
  117. Try dissabling CUDA for pytorch — galbramc / detail
  118. Look for fatal msvc errors — galbramc / detail
  119. Look for fatal gnu/clang errors — galbramc / detail
  120. Revert to serveCSM for plugs — galbramc / detail
  121. Update lingering serveCSM to serveESP — galbramc / detail
  122. Very strange... — galbramc / detail
  123. Allow multiple csm patterns — galbramc / detail
  124. Only check error handling when running all csm files — galbramc / detail
  125. Support changing outLevel and running select files — galbramc / detail
  126. Don't do jlEGADS testing just yet — galbramc / detail
  127. Revert ESP_venv for ESP_Beta — galbramc / detail
  128. Move virtualenv into ESP directory — galbramc / detail
  129. Only run minimal CAPS examples in beta — galbramc / detail
  130. Install torch for beta — galbramc / detail
  131. pip install torch for corsair — galbramc / detail
  132. Smartsr error log parse — galbramc / detail