diff --git a/CMakeLists.txt b/CMakeLists.txt index b71bb6e598e4924d81dc24e6a0f8c9947a22209f..cb1c70ae5bc942e5bdc681668e9e25142943e487 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -148,7 +148,7 @@ set(GMSH_API contrib/DiscreteIntegration/Integration3D.h contrib/HighOrderMeshOptimizer/OptHOM.h contrib/HighOrderMeshOptimizer/OptHomMesh.h contrib/HighOrderMeshOptimizer/OptHomRun.h contrib/HighOrderMeshOptimizer/ParamCoord.h - contrib/HighOrderMeshOptimizer/OptHomFastCurving.h + contrib/HighOrderMeshOptimizer/OptHomFastCurving.h contrib/HighOrderMeshOptimizer/OptHomIntegralBoundaryDist.h contrib/HighOrderMeshOptimizer/CADDistances.h contrib/HighOrderMeshOptimizer/OptHomObjContribScaledJac.h @@ -1054,7 +1054,7 @@ if(HAVE_SOLVER) message(STATUS "Warning: Disabling Taucs (requires METIS)") endif(HAVE_METIS) endif(ENABLE_TAUCS AND HAVE_BLAS AND HAVE_LAPACK) - + if(ENABLE_MUMPS AND HAVE_BLAS AND HAVE_LAPACK) set(MUMPS_LIBS_REQUIRED smumps dmumps cmumps zmumps mumps_common pord) if(NOT ENABLE_MPI) @@ -1154,7 +1154,7 @@ if(ENABLE_OCC) unset(OCC_LIB CACHE) endforeach(OCC) list(LENGTH OCC_LIBS NUM_OCC_LIBS) - endif(OCC_LIBS) + endif(OCC_LIBS) if(NUM_OCC_LIBS EQUAL NUM_OCC_LIBS_REQUIRED) set_config_option(HAVE_OCC "OpenCASCADE") list(APPEND EXTERNAL_LIBRARIES ${OCC_LIBS}) diff --git a/Common/CommandLine.cpp b/Common/CommandLine.cpp index 4c611ebc2687b6a3facff5ed84f9bb6711e0a737..19c233f24cb160fcbfcc24bc40322283a00c8005 100644 --- a/Common/CommandLine.cpp +++ b/Common/CommandLine.cpp @@ -74,7 +74,7 @@ std::vector<std::pair<std::string, std::string> > GetUsage() s.push_back(mp("-o file", "Specify output file name")); s.push_back(mp("-format string", "Select output mesh format (auto (default), msh, " "msh1, msh2, unv, vrml, ply2, stl, mesh, bdf, cgns, " - "p3d, diff, med, ...)")); + "p3d, diff, med, neu, ...)")); s.push_back(mp("-bin", "Use binary format when available")); s.push_back(mp("-refine", "Perform uniform mesh refinement, then exit")); s.push_back(mp("-reclassify", "Reclassify mesh, then exit")); @@ -106,7 +106,7 @@ std::vector<std::pair<std::string, std::string> > GetUsage() s.push_back(mp("-rand float", "Set random perturbation factor")); s.push_back(mp("-bgm file", "Load background mesh from file")); s.push_back(mp("-check", "Perform various consistency checks on mesh")); - s.push_back(mp("-ignorePartBound", "Ignore partition boundaries")); + s.push_back(mp("-ignorePartBound", "Ignore partition boundaries")); s.push_back(mp("-ignorePeriocity", "Ignore periodic boundaries")); s.push_back(mp("-oneFilePerPart", "Save mesh partitions in separate files")); #if defined(HAVE_FLTK) @@ -1163,5 +1163,3 @@ void GetOptions(int argc, char *argv[]) if(CTX::instance()->terminal == 99) CTX::instance()->terminal = terminal; } - - diff --git a/Common/CreateFile.cpp b/Common/CreateFile.cpp index 7ec744426dacf7c2091fc665bf8c63b64f8c7d16..532c68dcabf1d64ecf205a15b9bd0f4f93e63b30 100644 --- a/Common/CreateFile.cpp +++ b/Common/CreateFile.cpp @@ -79,6 +79,7 @@ int GetFileFormatFromExtension(const std::string &ext) else if(ext == ".stp") return FORMAT_STEP; else if(ext == ".iges") return FORMAT_IGES; else if(ext == ".igs") return FORMAT_IGES; + else if(ext == ".neu") return FORMAT_NEU; else return -1; } @@ -133,6 +134,7 @@ std::string GetDefaultFileName(int format) case FORMAT_BREP: name += ".brep"; break; case FORMAT_IGES: name += ".iges"; break; case FORMAT_STEP: name += ".step"; break; + case FORMAT_NEU: name += ".neu"; break; default: break; } return name; @@ -396,6 +398,11 @@ void CreateOutputFile(const std::string &fileName, int format, GModel::current()->writeOCCSTEP(name); break; + case FORMAT_NEU: + GModel::current()->writeNEU + (name, CTX::instance()->mesh.saveAll, CTX::instance()->mesh.scalingFactor); + break; + #if defined(HAVE_FLTK) case FORMAT_PPM: case FORMAT_YUV: diff --git a/Common/GmshDefines.h b/Common/GmshDefines.h index 630462e3fd90e1cf2571754bc7be9ec00270d903..770752ca4961d2d75d57aafcad89db134f538d95 100644 --- a/Common/GmshDefines.h +++ b/Common/GmshDefines.h @@ -7,54 +7,55 @@ #define _GMSH_DEFINES_H_ // IO file formats (numbers should not be changed) -#define FORMAT_MSH 1 -#define FORMAT_UNV 2 -#define FORMAT_GREF 3 -#define FORMAT_XPM 4 -#define FORMAT_PS 5 -#define FORMAT_BMP 6 -#define FORMAT_GIF 7 -#define FORMAT_GEO 8 -#define FORMAT_JPEG 9 -#define FORMAT_AUTO 10 -#define FORMAT_PPM 11 -#define FORMAT_YUV 12 -#define FORMAT_DMG 13 -#define FORMAT_SMS 14 -#define FORMAT_OPT 15 -#define FORMAT_VTK 16 -#define FORMAT_MPEG 17 -#define FORMAT_TEX 18 -#define FORMAT_VRML 19 -#define FORMAT_EPS 20 -#define FORMAT_MAIL 21 -#define FORMAT_PNG 22 -#define FORMAT_TXT 23 -#define FORMAT_PDF 24 -#define FORMAT_RMED 25 -#define FORMAT_POS 26 -#define FORMAT_STL 27 -#define FORMAT_P3D 28 -#define FORMAT_SVG 29 -#define FORMAT_MESH 30 -#define FORMAT_BDF 31 -#define FORMAT_CGNS 32 -#define FORMAT_MED 33 -#define FORMAT_DIFF 34 -#define FORMAT_BREP 35 -#define FORMAT_STEP 36 -#define FORMAT_IGES 37 -#define FORMAT_IR3 38 -#define FORMAT_INP 39 -#define FORMAT_PLY2 40 -#define FORMAT_CELUM 41 -#define FORMAT_SU2 42 +#define FORMAT_MSH 1 +#define FORMAT_UNV 2 +#define FORMAT_GREF 3 +#define FORMAT_XPM 4 +#define FORMAT_PS 5 +#define FORMAT_BMP 6 +#define FORMAT_GIF 7 +#define FORMAT_GEO 8 +#define FORMAT_JPEG 9 +#define FORMAT_AUTO 10 +#define FORMAT_PPM 11 +#define FORMAT_YUV 12 +#define FORMAT_DMG 13 +#define FORMAT_SMS 14 +#define FORMAT_OPT 15 +#define FORMAT_VTK 16 +#define FORMAT_MPEG 17 +#define FORMAT_TEX 18 +#define FORMAT_VRML 19 +#define FORMAT_EPS 20 +#define FORMAT_MAIL 21 +#define FORMAT_PNG 22 +#define FORMAT_TXT 23 +#define FORMAT_PDF 24 +#define FORMAT_RMED 25 +#define FORMAT_POS 26 +#define FORMAT_STL 27 +#define FORMAT_P3D 28 +#define FORMAT_SVG 29 +#define FORMAT_MESH 30 +#define FORMAT_BDF 31 +#define FORMAT_CGNS 32 +#define FORMAT_MED 33 +#define FORMAT_DIFF 34 +#define FORMAT_BREP 35 +#define FORMAT_STEP 36 +#define FORMAT_IGES 37 +#define FORMAT_IR3 38 +#define FORMAT_INP 39 +#define FORMAT_PLY2 40 +#define FORMAT_CELUM 41 +#define FORMAT_SU2 42 #define FORMAT_MPEG_PREVIEW 43 -#define FORMAT_PGF 44 -#define FORMAT_PVTU 45 -#define FORMAT_X3D 46 -#define FORMAT_TOCHNOG 47 -#define FORMAT_TIKZ 48 +#define FORMAT_PGF 44 +#define FORMAT_PVTU 45 +#define FORMAT_X3D 46 +#define FORMAT_TOCHNOG 47 +#define FORMAT_TIKZ 48 +#define FORMAT_NEU 49 // Element types #define TYPE_PNT 1 diff --git a/Fltk/graphicWindow.cpp b/Fltk/graphicWindow.cpp index 951a0687d017e480efd870f5cc2349613d5986f6..257ffe7c0f6c1174e9045cc8308a846c63b59226 100644 --- a/Fltk/graphicWindow.cpp +++ b/Fltk/graphicWindow.cpp @@ -316,6 +316,8 @@ static int _save_vrml(const char *name){ return genericMeshFileDialog (name, "VRML Options", FORMAT_VRML, false, false); } static int _save_ply2(const char *name){ return genericMeshFileDialog (name, "PLY2 Options", FORMAT_PLY2, false, false); } +static int _save_neu(const char *name){ return genericMeshFileDialog + (name, "NEU Options", FORMAT_NEU, false, false); } static int _save_eps(const char *name){ return gl2psFileDialog (name, "EPS Options", FORMAT_EPS); } static int _save_gif(const char *name){ return gifFileDialog(name); } @@ -380,6 +382,7 @@ static int _save_auto(const char *name) case FORMAT_STL : return _save_stl(name); case FORMAT_VRML : return _save_vrml(name); case FORMAT_PLY2 : return _save_ply2(name); + case FORMAT_NEU : return _save_neu(name); case FORMAT_EPS : return _save_eps(name); case FORMAT_GIF : return _save_gif(name); case FORMAT_JPEG : return _save_jpeg(name); @@ -436,6 +439,7 @@ static void file_export_cb(Fl_Widget *w, void *data) {"Mesh - Tochnog" TT "*.dat", _save_tochnog}, {"Mesh - PLY2 Surface" TT "*.ply2", _save_ply2}, {"Mesh - SU2" TT "*.su2", _save_su2}, + {"Mesh - GAMBIT Neutral File" TT "*.neu", _save_neu}, {"Post-processing - Gmsh POS" TT "*.pos", _save_view_pos}, {"Post-processing - X3D (X3D)" TT "*.x3d", _save_view_x3d}, #if defined(HAVE_MED) diff --git a/Geo/CMakeLists.txt b/Geo/CMakeLists.txt index 2ac9ea624b919b808d1946d9943ee9b20984b87d..e8d73035adf0db89d78b9648e7a62cee26ddba3c 100644 --- a/Geo/CMakeLists.txt +++ b/Geo/CMakeLists.txt @@ -15,7 +15,7 @@ set(SRC gmshSurface.cpp OCCVertex.cpp OCCEdge.cpp OCCFace.cpp OCCRegion.cpp GenericVertex.cpp GenericEdge.cpp GenericFace.cpp GenericRegion.cpp - discreteEdge.cpp discreteFace.cpp discreteDiskFace.cpp discreteRegion.cpp + discreteEdge.cpp discreteFace.cpp discreteDiskFace.cpp discreteRegion.cpp fourierEdge.cpp fourierFace.cpp fourierProjectionFace.cpp ACISVertex.cpp ACISEdge.cpp @@ -25,12 +25,12 @@ set(SRC GModelVertexArrays.cpp GModelFactory.cpp GModelIO_GEO.cpp GModelIO_ACIS.cpp GModelIO_OCC.cpp GModelIO_TOCHNOG.cpp - GModelIO_Fourier.cpp - GModelIO_MSH.cpp GModelIO_MSH2.cpp GModelIO_VTK.cpp GModelIO_POS.cpp - GModelIO_CGNS.cpp GModelIO_MED.cpp GModelIO_MESH.cpp GModelIO_STL.cpp - GModelIO_PLY.cpp GModelIO_VRML.cpp GModelIO_UNV.cpp GModelIO_BDF.cpp + GModelIO_Fourier.cpp + GModelIO_MSH.cpp GModelIO_MSH2.cpp GModelIO_VTK.cpp GModelIO_POS.cpp + GModelIO_CGNS.cpp GModelIO_MED.cpp GModelIO_MESH.cpp GModelIO_STL.cpp + GModelIO_PLY.cpp GModelIO_VRML.cpp GModelIO_UNV.cpp GModelIO_BDF.cpp GModelIO_IR3.cpp GModelIO_DIFF.cpp GModelIO_GEOM.cpp GModelIO_INP.cpp - GModelIO_MAIL.cpp GModelIO_P3D.cpp GModelIO_CELUM.cpp + GModelIO_MAIL.cpp GModelIO_P3D.cpp GModelIO_CELUM.cpp GModelIO_NEU.cpp GModelIO_ACTRAN.cpp GModelIO_SU2.cpp GModelIO_SAMCEF.cpp ExtrudeParams.cpp Geo.cpp @@ -51,5 +51,5 @@ set(SRC MVertexBoundaryLayerData.cpp ) -file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) +file(GLOB HDR RELATIVE ${CMAKE_CURRENT_SOURCE_DIR} *.h) append_gmsh_src(Geo "${SRC};${HDR}") diff --git a/Geo/GModel.h b/Geo/GModel.h index b37ed3715174d4a968d805eae56ba4c54b2bdd43..4f382250a7f521dbd3bcaf37079279dabe623f72 100644 --- a/Geo/GModel.h +++ b/Geo/GModel.h @@ -724,6 +724,9 @@ class GModel { // SU2 mesh file int writeSU2(const std::string &name, bool saveAll, double scalingFactor); + + // GAMBIT neutral mesh file (.neu) + int writeNEU(const std::string &name, bool saveAll, double scalingFactor); }; #endif diff --git a/Geo/GModelIO_NEU.cpp b/Geo/GModelIO_NEU.cpp new file mode 100644 index 0000000000000000000000000000000000000000..31461a1098c66deae293f5f3b57dec3415c5d154 --- /dev/null +++ b/Geo/GModelIO_NEU.cpp @@ -0,0 +1,286 @@ +// Gmsh - Copyright (C) 1997-2017 C. Geuzaine, J.-F. Remacle +// +// See the LICENSE.txt file for license information. Please report all +// bugs and problems to the public mailing list <gmsh@onelab.info>. + +#include <algorithm> +#include <limits> +#if __cplusplus >= 201103L +#include <unordered_map> +#else +#include <map> +#endif +#include "GModel.h" +#include "OS.h" +#include "MTriangle.h" +#include "MTetrahedron.h" + +namespace +{ + static const unsigned GAMBIT_TYPE_EDGE = 1; + static const unsigned GAMBIT_TYPE_QUAD = 2; + static const unsigned GAMBIT_TYPE_TRI = 3; + static const unsigned GAMBIT_TYPE_TET = 6; + + // This struct allows us to take advantage of C++11 unordered_map while + // maintaining backwards compatibility with C++03 + template<typename Key, typename Value> + struct hashMap { + #if __cplusplus >= 201103L + typedef std::unordered_map<Key, Value> _; + #else + typedef std::map<Key, Value> _; + #endif + }; + + const hashMap<std::string, unsigned>::_::value_type rawData[] = { + hashMap<std::string, unsigned>::_::value_type("UNSPECIFIED", 0), + hashMap<std::string, unsigned>::_::value_type("AXIS", 1), + hashMap<std::string, unsigned>::_::value_type("CONJUGATE", 2), + hashMap<std::string, unsigned>::_::value_type("CONVECTION", 3), + hashMap<std::string, unsigned>::_::value_type("CYCLIC", 4), + hashMap<std::string, unsigned>::_::value_type("DEAD", 5), + hashMap<std::string, unsigned>::_::value_type("ELEMENT_SID", 6), + hashMap<std::string, unsigned>::_::value_type("ESPECIES", 7), + hashMap<std::string, unsigned>::_::value_type("EXHAUST_FAN", 8), + hashMap<std::string, unsigned>::_::value_type("FAN", 9), + hashMap<std::string, unsigned>::_::value_type("FREE_SURFACE", 10), + hashMap<std::string, unsigned>::_::value_type("GAP", 11), + hashMap<std::string, unsigned>::_::value_type("INFLOW", 12), + hashMap<std::string, unsigned>::_::value_type("INLET", 13), + hashMap<std::string, unsigned>::_::value_type("INLET_VENT", 14), + hashMap<std::string, unsigned>::_::value_type("INTAKE_FAN", 15), + hashMap<std::string, unsigned>::_::value_type("INTERFACE", 16), + hashMap<std::string, unsigned>::_::value_type("INTERIOR", 17), + hashMap<std::string, unsigned>::_::value_type("INTERNAL", 18), + hashMap<std::string, unsigned>::_::value_type("LIVE", 19), + hashMap<std::string, unsigned>::_::value_type("MASS_FLOW_INLET", 20), + hashMap<std::string, unsigned>::_::value_type("MELT", 21), + hashMap<std::string, unsigned>::_::value_type("MELT_INTERFACE", 22), + hashMap<std::string, unsigned>::_::value_type("MOVING_BOUNDARY", 23), + hashMap<std::string, unsigned>::_::value_type("NODE", 24), + hashMap<std::string, unsigned>::_::value_type("OUTFLOW", 25), + hashMap<std::string, unsigned>::_::value_type("OUTLET", 26), + hashMap<std::string, unsigned>::_::value_type("OUTLET_VENT", 27), + hashMap<std::string, unsigned>::_::value_type("PERIODIC", 28), + hashMap<std::string, unsigned>::_::value_type("PLOT", 29), + hashMap<std::string, unsigned>::_::value_type("POROUS", 30), + hashMap<std::string, unsigned>::_::value_type("POROUS_JUMP", 31), + hashMap<std::string, unsigned>::_::value_type("PRESSURE", 32), + hashMap<std::string, unsigned>::_::value_type("PRESSURE_FAR_FIELD", 33), + hashMap<std::string, unsigned>::_::value_type("PRESSURE_INFLOW", 34), + hashMap<std::string, unsigned>::_::value_type("PRESSURE_INLET", 35), + hashMap<std::string, unsigned>::_::value_type("PRESSURE_OUTFLOW", 36), + hashMap<std::string, unsigned>::_::value_type("PRESSURE_OUTLET", 37), + hashMap<std::string, unsigned>::_::value_type("RADIATION", 38), + hashMap<std::string, unsigned>::_::value_type("RADIATOR", 39), + hashMap<std::string, unsigned>::_::value_type("RECIRCULATION_INLET", 40), + hashMap<std::string, unsigned>::_::value_type("RECIRCULATION_OUTLET", 41), + hashMap<std::string, unsigned>::_::value_type("SLIP", 42), + hashMap<std::string, unsigned>::_::value_type("SREACTION", 43), + hashMap<std::string, unsigned>::_::value_type("SURFACE", 44), + hashMap<std::string, unsigned>::_::value_type("SYMMETRY", 45), + hashMap<std::string, unsigned>::_::value_type("TRACTION", 46), + hashMap<std::string, unsigned>::_::value_type("TRAJECTORY", 47), + hashMap<std::string, unsigned>::_::value_type("VELOCITY", 48), + hashMap<std::string, unsigned>::_::value_type("VELOCITY_INLET", 49), + hashMap<std::string, unsigned>::_::value_type("VENT", 50), + hashMap<std::string, unsigned>::_::value_type("WALL", 51), + hashMap<std::string, unsigned>::_::value_type("SPRING", 52), + }; + static const hashMap<std::string, unsigned>::_ boundaryCodeMap(rawData, rawData + (sizeof rawData / sizeof rawData[0])); + + // Gambit numbers its faces slightly differently + static const unsigned GAMBIT_FACE_MAP[4] = {1,2,4,3}; + + unsigned const gambitBoundaryCode(std::string name) + { + std::transform(name.begin(), name.end(),name.begin(), ::toupper); + hashMap<std::string, unsigned>::_::const_iterator code = boundaryCodeMap.find(name); + return code == boundaryCodeMap.end() ? 0 : code->second; + } + + typedef std::pair<unsigned, unsigned> TetFacePair; + typedef hashMap<unsigned, std::vector<TetFacePair> >::_ IDTetFaceMap; + + bool const sortBCs(TetFacePair const& lhs, TetFacePair const& rhs) + { + return lhs.first < rhs.first; + } + + IDTetFaceMap const gatherBC(GModel* gm) + { + // create association map for vertices and faces + hashMap<unsigned, std::vector<unsigned> >::_ vertmap; + for (GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it) { + for (unsigned i = 0; i < (*it)->triangles.size(); ++i) { + MTriangle* tri = (*it)->triangles[i]; + for (int j = 0; j < tri->getNumVertices(); ++j) { + vertmap[tri->getVertex(j)->getNum()].push_back(tri->getNum()); + } + } + } + + // determine which faces belong to which tetrahedra by comparing vertices + IDTetFaceMap tetfacemap; + for (GModel::riter it = gm->firstRegion(); it != gm->lastRegion(); ++it) { + for (unsigned i = 0; i < (*it)->tetrahedra.size(); ++i) { + MTetrahedron* tet = (*it)->tetrahedra[i]; + for (int faceNum = 0; faceNum < tet->getNumFaces(); ++faceNum) { + std::vector<MVertex*> verts; + tet->getFaceVertices(faceNum, verts); + + std::vector<unsigned> current = vertmap[verts[0]->getNum()]; + for (unsigned j = 1; j < verts.size() && current.size() != 0; ++j) { + std::vector<unsigned> common_data; + set_intersection(current.begin(), current.end(), + vertmap[verts[j]->getNum()].begin(), + vertmap[verts[j]->getNum()].end(), + std::back_inserter(common_data)); + current = common_data; + } + if (current.size() == 1) { + tetfacemap[current[0]].push_back( + TetFacePair(tet->getNum(), GAMBIT_FACE_MAP[faceNum])); + } + } + } + } + + // populate boundary conditions for tetrahedra given triangle physicals + IDTetFaceMap boundaryConditions; + for (GModel::fiter it = gm->firstFace(); it != gm->lastFace(); ++it) { + if ((*it)->physicals.size()) { + for (unsigned i = 0; i < (*it)->physicals.size(); ++i) { + unsigned phys = (*it)->physicals[i]; + for (unsigned j = 0; j < (*it)->triangles.size(); ++j) { + MTriangle* tri = (*it)->triangles[j]; + IDTetFaceMap::iterator tets = tetfacemap.find(tri->getNum()); + if (tets != tetfacemap.end()) { + for (unsigned tet = 0; tet < tets->second.size(); ++tet) { + boundaryConditions[phys].push_back(tets->second[tet]); + } + } + } + } + } + } + + return boundaryConditions; + } +} + +// for a specification of the GAMBIT neutral format: +// http://web.stanford.edu/class/me469b/handouts/gambit_write.pdf +int GModel::writeNEU(const std::string &name, bool saveAll, + double scalingFactor) +{ + FILE* fp = Fopen(name.c_str(), "w"); + if (!fp) { + Msg::Error("Unable to open file '%s'", name.c_str()); + return 0; + } + + // gather tetrahedra and id normalization information + unsigned numTetrahedra = 0; + int lowestId = std::numeric_limits<int>::max(); + hashMap<unsigned, std::vector<unsigned> >::_ elementGroups; + for (riter it = firstRegion(); it != lastRegion(); ++it) { + if (saveAll || (*it)->physicals.size()) { + numTetrahedra += (*it)->tetrahedra.size(); + + for (unsigned phys = 0; phys < (*it)->physicals.size(); ++phys) { + for (unsigned i = 0; i < (*it)->tetrahedra.size(); ++i) { + MTetrahedron* tet = (*it)->tetrahedra[i]; + elementGroups[(*it)->physicals[phys]].push_back(tet->getNum()); + + if (tet->getNum() < lowestId) lowestId = tet->getNum()-1; + } + } + } + } + + IDTetFaceMap boundaryConditions = gatherBC(this); + + // Metadata + fprintf(fp, " CONTROL INFO 2.0.0\n"); + fprintf(fp, "** GAMBIT NEUTRAL FILE\n"); + fprintf(fp, "Gmsh mesh in GAMBIT neutral file format\n"); + fprintf(fp, "PROGRAM: Gambit VERSION: 2.0.0\n"); + + char datestring[256]; + time_t rawtime; + struct tm* timeinfo; + time(&rawtime); + timeinfo = localtime(&rawtime); + strftime(datestring, sizeof(datestring), "%c", timeinfo); + fprintf(fp, "%s\n", datestring); + + fprintf(fp, " NUMNP NELEM NGRPS NBSETS NDFCD NDFVL\n"); + fprintf(fp, " %9d %9d %9lu %9lu %9d %9d\n", indexMeshVertices(saveAll), numTetrahedra, + elementGroups.size(), boundaryConditions.size(), getDim(), + getDim()); + fprintf(fp, "ENDOFSECTION\n"); + + // Nodes + fprintf(fp, " NODAL COORDINATES 2.0.0\n"); + std::vector<GEntity*> entities; + getEntities(entities); + for (unsigned i = 0; i < entities.size(); ++i) { + for (unsigned j = 0; j < entities[i]->mesh_vertices.size(); ++j) { + entities[i]->mesh_vertices[j]->writeNEU(fp, getDim(), scalingFactor); + } + } + fprintf(fp, "ENDOFSECTION\n"); + + // Elements + fprintf(fp, " ELEMENTS/CELLS 2.0.0\n"); + for (riter it = firstRegion(); it != lastRegion(); ++it) { + unsigned numPhys = (*it)->physicals.size(); + if (saveAll || numPhys) { + for (unsigned i = 0; i < (*it)->tetrahedra.size(); ++i) { + (*it)->tetrahedra[i]->writeNEU(fp, GAMBIT_TYPE_TET, lowestId, + numPhys ? (*it)->physicals[0] : 0); + } + } + } + fprintf(fp, "ENDOFSECTION\n"); + + // Element Groups + + for (hashMap<unsigned, std::vector<unsigned> >::_::const_iterator + it = elementGroups.begin(); it != elementGroups.end(); ++it) { + fprintf(fp, " ELEMENT GROUP 2.0.0\n"); + fprintf(fp, "GROUP: %10d ELEMENTS: %10lu MATERIAL: 0 NFLAGS: %10d\n", it->first, it->second.size(), 1); + fprintf(fp, "Material group %d\n", it->first); + fprintf(fp, " 0"); + + for (unsigned i = 0; i < it->second.size(); ++i) { + if (i % 10 == 0) { + fprintf(fp, "\n"); + } + fprintf(fp, "%8d", it->second[i] - lowestId); + } + fprintf(fp, "\n"); + fprintf(fp, "ENDOFSECTION\n"); + } + + // Boundary Conditions + for (IDTetFaceMap::iterator it = boundaryConditions.begin(); + it != boundaryConditions.end(); ++it) { + fprintf(fp, " BOUNDARY CONDITIONS 2.0.0\n"); + + std::string const regionName = getPhysicalName(2, it->first); + fprintf(fp, "%32s%8d%8lu%8d%8d\n", regionName.c_str(), 1, it->second.size(), 0, gambitBoundaryCode(regionName)); + std::sort(it->second.begin(), it->second.end(), sortBCs); + std::vector<TetFacePair>::iterator tfp = it->second.begin(); + for (std::vector<TetFacePair>::iterator tfp = it->second.begin(); tfp != it->second.end(); ++tfp) { + fprintf(fp, "%10d %5d %5d\n", tfp->first-lowestId, GAMBIT_TYPE_TET, tfp->second); + } + + fprintf(fp, "ENDOFSECTION\n"); + } + + fclose(fp); + return 1; +} diff --git a/Geo/MElement.cpp b/Geo/MElement.cpp index 05689e94f56b26f12960f6908fd4d999707f25b3..4914775dd8b4b36cbc797055e4c4ae0f1564349f 100644 --- a/Geo/MElement.cpp +++ b/Geo/MElement.cpp @@ -1338,6 +1338,19 @@ void MElement::writeMESH(FILE *fp, int elementTagType, int elementary, if(physical < 0) reverse(); } +void MElement::writeNEU(FILE *fp, unsigned gambitType, int idAdjust, int phys) +{ + if(phys < 0) reverse(); + + fprintf(fp, "%8d %2d %2d ", _num-idAdjust, gambitType, getNumVertices()); + for(int i = 0; i < getNumVertices(); ++i) { + fprintf(fp, "%8d", getVertex(i)->getIndex()); + } + fprintf(fp, "\n"); + + if(phys < 0) reverse(); +} + void MElement::writeIR3(FILE *fp, int elementTagType, int num, int elementary, int physical) { diff --git a/Geo/MElement.h b/Geo/MElement.h index 20b7f37ffee9b91ce44b6cb17b833d9015387537..cf86a181b4c360fc157a8623725ac20c5c056599 100644 --- a/Geo/MElement.h +++ b/Geo/MElement.h @@ -385,6 +385,7 @@ class MElement virtual void writeTOCHNOG(FILE *fp, int num); virtual void writeMESH(FILE *fp, int elementTagType=1, int elementary=1, int physical=0); + virtual void writeNEU(FILE *fp, unsigned gambitType, int adjust, int phys=0); virtual void writeIR3(FILE *fp, int elementTagType, int num, int elementary, int physical); virtual void writeBDF(FILE *fp, int format=0, int elementTagType=1, diff --git a/Geo/MVertex.cpp b/Geo/MVertex.cpp index c56f6cedf6d4da65713d9930c95706a67d9028f6..cd1535f1d86152f204593e1963c6472f9c11bcb9 100644 --- a/Geo/MVertex.cpp +++ b/Geo/MVertex.cpp @@ -270,6 +270,26 @@ void MVertex::writeMESH(FILE *fp, double scalingFactor) _ge ? _ge->tag() : 0); } +void MVertex::writeNEU(FILE *fp, int dim, double scalingFactor) +{ + if(_index < 0) return; // negative index vertices are never saved + + switch(dim) { + case 3: + fprintf(fp, "%10d%20.11e%20.11e%20.11e\n", + _index, x() * scalingFactor, y() * scalingFactor, + z() * scalingFactor); + break; + case 2: + fprintf(fp, "%10d%20.11e%20.11e\n", + _index, x() * scalingFactor, y() * scalingFactor); + break; + case 1: + fprintf(fp, "%10d%20.11e\n", _index, x() * scalingFactor); + break; + } +} + static void double_to_char8(double val, char *str) { if(val >= 1.e6) diff --git a/Geo/MVertex.h b/Geo/MVertex.h index 0467a86606a63e5efab81e3e8687b247d235ac67..df093d162aa6a33fc6606b177298adeb8f03724d 100644 --- a/Geo/MVertex.h +++ b/Geo/MVertex.h @@ -100,6 +100,7 @@ class MVertex{ bool bigEndian=false); void writeTOCHNOG(FILE *fp, int dim, double scalingFactor=1.0); void writeMESH(FILE *fp, double scalingFactor=1.0); + void writeNEU(FILE *fp, int dim, double scalingFactor=1.0); void writeBDF(FILE *fp, int format=0, double scalingFactor=1.0); void writeINP(FILE *fp, double scalingFactor=1.0); void writeDIFF(FILE *fp, bool binary, double scalingFactor=1.0);