Get created elements and nodes to write to binary file.
Remote version. Fill premeshed faces considering element orientation. Dumping created volumetric elements considering new nodes and old nodes from faces.
Intermermedial commit.
Code clean up.
Final tested version of GMSH_3D_Remote mesher.
{
};
+ /*!
+ * GMSHPlugin_GMSH: interface of "Gmsh" algorithm
+ */
+ interface GMSHPlugin_GMSH_3D_Remote : GMSHPlugin::GMSHPlugin_GMSH_3D
+ {
+ };
+
/*!
* GMSHPlugin_GMSH_2D: interface of "Gmsh_2D" algorithm
*/
${MEDCOUPLING_INCLUDE_DIRS}
${Boost_INCLUDE_DIRS}
${OMNIORB_INCLUDE_DIR}
- ${GMSH_INCLUDE_DIRS}
${PROJECT_BINARY_DIR}/idl
)
+#Avoid compilation warnings from gmsh headers
+INCLUDE_DIRECTORIES( SYSTEM ${GMSH_INCLUDE_DIRS} )
+
# additional preprocessor / compiler flags
ADD_DEFINITIONS(
${OMNIORB_DEFINITIONS}
GMSHPlugin_GMSH_2D.hxx
GMSHPlugin_GMSH_2D_i.hxx
GMSHPlugin_GMSH_3D.hxx
+ GMSHPlugin_GMSH_3D_SA.hxx
+ GMSHPlugin_GMSH_3D_Remote.hxx
+ GMSHPlugin_GMSH_3D_Remote_i.hxx
GMSHPlugin_GMSH_3D_i.cxx
GMSHPlugin_GMSH.hxx
GMSHPlugin_GMSH_i.hxx
GMSHPlugin_GMSH_2D.cxx
GMSHPlugin_GMSH_2D_i.cxx
GMSHPlugin_GMSH_3D.cxx
+ GMSHPlugin_GMSH_3D_SA.cxx
+ GMSHPlugin_GMSH_3D_Remote.cxx
+ GMSHPlugin_GMSH_3D_Remote_i.cxx
GMSHPlugin_GMSH_3D_i.cxx
GMSHPlugin_GMSH.cxx
GMSHPlugin_GMSH_i.cxx
GMSHPlugin_i.cxx
)
+SET(GmshRunner_SOURCES
+ GMSHPlugin_Runner_main.cxx
+)
+
# --- scripts ---
# scripts / static
TARGET_LINK_LIBRARIES(GMSHEngine ${_link_LIBRARIES} )
INSTALL(TARGETS GMSHEngine EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS})
+ADD_EXECUTABLE(GMSHPlugin_Runner ${GmshRunner_SOURCES})
+TARGET_LINK_LIBRARIES(GMSHPlugin_Runner ${_link_LIBRARIES} GMSHEngine )
+INSTALL(TARGETS GMSHPlugin_Runner EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_BINS})
+
INSTALL(FILES ${GMSHEngine_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS})
SALOME_INSTALL_SCRIPTS("${_bin_SCRIPTS}" ${SALOME_INSTALL_PYTHON}/salome/GMSHPlugin)
GMSH = "GMSH"
GMSH_3D = "GMSH_3D"
GMSH_2D = "GMSH_2D"
+GMSH_3D_Remote = "GMSH_3D_Remote"
## Base of all GMSH algorithms.
#
hypType = "GMSH_Parameters"
elif self.algoType == GMSH_3D:
hypType = "GMSH_Parameters_3D"
+ elif self.algoType == GMSH_3D_Remote:
+ hypType = "GMSH_Parameters_3D"
if self.params and self.params.GetName() != hypType:
self.mesh.RemoveHypothesis( self.params, self.geom )
class GMSH_3D_Algorithm(GMSH_Algorithm):
- meshMethod = "Tetrahedron"
- algoType = GMSH_3D
+ meshMethod = "Tetrahedron"
+ algoType = GMSH_3D
+
+ ## Private constructor.
+ def __init__(self, mesh, geom=0):
+ GMSH_Algorithm.__init__(self, mesh, geom)
- ## Private constructor.
- def __init__(self, mesh, geom=0):
- GMSH_Algorithm.__init__(self, mesh, geom)
+
+class GMSH_3D_Remote_Algorithm(GMSH_Algorithm):
+ meshMethod = "Tetrahedron"
+ algoType = GMSH_3D_Remote
+
+ ## Private constructor.
+ def __init__(self, mesh, geom=0):
+ GMSH_Algorithm.__init__(self, mesh, geom)
\ No newline at end of file
//
#include "GMSHPlugin_GMSH_3D.hxx"
#include "GMSHPlugin_Hypothesis_2D.hxx"
-#include "GMSHPlugin_Mesher.hxx"
#include <SMESH_Gen.hxx>
#include <SMESH_ControlsDef.hxx>
SMESH_Hypothesis::Hypothesis_Status& aStatus)
{
MESSAGE("GMSHPlugin_GMSH::CheckHypothesis");
-
_hypothesis = NULL;
const list<const SMESHDS_Hypothesis*>& hyps = GetUsedHypothesis(aMesh, aShape);
#define _GMSHPlugin_GMSH_3D_HXX_
#include "GMSHPlugin_Defs.hxx"
+#include "GMSHPlugin_Mesher.hxx"
#include "SMESH_Algo.hxx"
#include "SMESH_subMesh.hxx"
--- /dev/null
+// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//=============================================================================
+// File : GMSHPlugin_GMSH_3D_Remote.hxx
+// Created : 09 Septembre 2023
+// Author : Cesar Conopoima (OCC)
+// Project : SALOME
+//=============================================================================
+//
+//
+
+#include "GMSHPlugin_GMSH_3D_Remote.hxx"
+#include "GMSHPlugin_Hypothesis.hxx"
+#include "Utils_SALOME_Exception.hxx"
+
+#include <SMESH_Gen.hxx>
+#include <SMESH_Mesh.hxx>
+#include <SMESH_ParallelMesh.hxx>
+#include <SMESH_MesherHelper.hxx>
+#include <SMESH_DriverShape.hxx>
+#include <SMESH_DriverMesh.hxx>
+#include <SMESHDS_Mesh.hxx>
+#include <SMESH_MeshLocker.hxx>
+#include <SMESH_ProxyMesh.hxx>
+
+#include <TopoDS.hxx>
+#include <TopExp.hxx>
+#include <TopExp_Explorer.hxx>
+
+#include <QString>
+#include <QProcess>
+
+#ifdef WIN32
+#include <filesystem>
+namespace fs = std::filesystem;
+#else
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+#endif
+
+//=============================================================================
+/*!
+ * Constructor
+ */
+//=============================================================================
+
+GMSHPlugin_GMSH_3D_Remote::GMSHPlugin_GMSH_3D_Remote(int hypId, SMESH_Gen * gen)
+ : GMSHPlugin_GMSH_3D(hypId, gen)
+{
+ _name = "GMSH_3D_Remote";
+}
+
+//=============================================================================
+/*!
+ * Destructor
+ */
+//=============================================================================
+
+GMSHPlugin_GMSH_3D_Remote::~GMSHPlugin_GMSH_3D_Remote()
+{
+}
+
+/**
+ * @brief Fill the structure netgen_param with the information from the hypothesis
+ *
+ * @param param_file name of the file to saven the gmsh parameter
+ * @param hyp the hypothesis
+ */
+void GMSHPlugin_GMSH_3D_Remote::exportGmshParams( const std::string param_file, const SMESHDS_Hypothesis* hyp )
+{
+ std::ofstream myfile(param_file);
+ if ( const GMSHPlugin_Hypothesis* gmshHypo = dynamic_cast<const GMSHPlugin_Hypothesis*>(hyp) )
+ {
+ myfile << 1 << std::endl; // Mark existence of correct hypothesis
+ myfile << (int) gmshHypo->Get2DAlgo() << std::endl;
+ myfile << (int) gmshHypo->Get3DAlgo() << std::endl;
+ myfile << (int) gmshHypo->GetRecomb2DAlgo() << std::endl;
+ myfile << (int) gmshHypo->GetRecombineAll() << std::endl;
+ myfile << (int) gmshHypo->GetSubdivAlgo() << std::endl;
+ myfile << (int) gmshHypo->GetRemeshAlgo() << std::endl;
+ myfile << (double) gmshHypo->GetSmouthSteps() << std::endl;
+ myfile << (double) gmshHypo->GetSizeFactor() << std::endl;
+#if GMSH_MAJOR_VERSION >=4 && GMSH_MINOR_VERSION >=10
+ myfile << (double) gmshHypo->GetMeshCurvatureSize() << std::endl;
+#elif
+ myfile << -1.0 << std::endl; // dummy value writte for conformity
+#endif
+ myfile << (double) gmshHypo->GetMaxSize() << std::endl;
+ myfile << (double) gmshHypo->GetMinSize() << std::endl;
+ myfile << (int) gmshHypo->GetSecondOrder() << std::endl;
+ myfile << (int) gmshHypo->GetUseIncomplElem() << std::endl;
+ if ( gmshHypo->GetCompoundOnEntries().size() > 0 )
+ {
+ TCompound defCompounds = gmshHypo->GetCompoundOnEntries();
+ for (TCompound::const_iterator it = defCompounds.begin(); it != defCompounds.end(); ++it )
+ {
+ std::string token = (it !=--defCompounds.end()) ? "," : "";
+ myfile << *it << token;
+ }
+ myfile << std::endl;
+ }
+ else
+ {
+ myfile << 0 << std::endl; // mark the absence of compounds
+ }
+ }
+ else
+ {
+ //Mark tha absence of parameters in the file
+ myfile << 0 << std::endl;
+ }
+ myfile.close();
+}
+
+//
+
+/**
+ * @brief write in a binary file the orientation for each surface element of the mesh
+ *
+ * @param aMesh The mesh
+ * @param aShape the shape associated to the mesh
+ * @param output_file name of the binary file
+ */
+void GMSHPlugin_GMSH_3D_Remote::exportElementOrientation(SMESH_Mesh& aMesh,
+ const TopoDS_Shape& aShape,
+ const std::string output_file)
+{
+ SMESH_MesherHelper helper(aMesh);
+ SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh ));
+ std::map<vtkIdType, bool> elemOrientation;
+
+ for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next())
+ {
+ const TopoDS_Shape& aShapeFace = exFa.Current();
+ int faceID = aMesh.GetMeshDS()->ShapeToIndex( aShapeFace );
+ bool isRev = false;
+ if ( helper.NbAncestors(aShapeFace, aMesh, aShape.ShapeType()) > 1 )
+ // IsReversedSubMesh() can work wrong on strongly curved faces,
+ // so we use it as less as possible
+ isRev = helper.IsReversedSubMesh( TopoDS::Face( aShapeFace ));
+
+ const SMESHDS_SubMesh * aSubMeshDSFace = proxyMesh->GetSubMesh( aShapeFace );
+ if ( !aSubMeshDSFace ) continue;
+
+ SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
+
+ while ( iteratorElem->more() ) // loop on elements on a geom face
+ {
+ // check mesh face
+ const SMDS_MeshElement* elem = iteratorElem->next();
+ if ( !elem )
+ error( COMPERR_BAD_INPUT_MESH, "Null element encounters");
+ if ( elem->NbCornerNodes() != 3 )
+ error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters");
+ elemOrientation[elem->GetID()] = isRev;
+ } // loop on elements on a face
+ } // loop on faces of a SOLID or SHELL
+
+ {
+ std::ofstream df(output_file, ios::out|ios::binary);
+ int size = elemOrientation.size();
+ df.write((char*)&size, sizeof(int));
+ for(auto const& [id, orient]:elemOrientation)
+ {
+ df.write((char*)&id, sizeof(vtkIdType));
+ df.write((char*)&orient, sizeof(bool));
+ }
+ df.close();
+ }
+}
+
+/**
+ * @brief Compute mesh associate to shape
+ *
+ * @param aMesh The mesh
+ * @param aShape The shape
+ * @return true fi there are some error
+ */
+bool GMSHPlugin_GMSH_3D_Remote::Compute(SMESH_Mesh& aMesh,
+ const TopoDS_Shape& aShape)
+{
+ {
+ SMESH_MeshLocker myLocker(&aMesh);
+ SMESH_Hypothesis::Hypothesis_Status hypStatus;
+ GMSHPlugin_GMSH_3D::CheckHypothesis(aMesh, aShape, hypStatus); //in this call the _hypothesis is defined!
+ }
+
+ SMESH_ParallelMesh& aParMesh = dynamic_cast<SMESH_ParallelMesh&>(aMesh);
+ // Temporary folder for run
+#ifdef WIN32
+ // On windows mesh does not have GetTmpFolder
+ fs::path tmp_folder = aParMesh.GetTmpFolder() / fs::path("Volume-%%%%-%%%%");
+#else
+ fs::path tmp_folder = aParMesh.GetTmpFolder() / fs::unique_path(fs::path("Volume-%%%%-%%%%"));
+#endif
+ fs::create_directories(tmp_folder);
+ // Using MESH2D generated after all triangles where created.
+ fs::path mesh_file= aParMesh.GetTmpFolder() / fs::path("Mesh2D.med");
+ fs::path element_orientation_file=tmp_folder / fs::path("element_orientation.dat");
+ fs::path new_element_file=tmp_folder / fs::path("new_elements.dat");
+ //fs::path tmp_mesh_file=tmp_folder / fs::path("tmp_mesh.med");
+ // Not used kept for debug
+ // fs::path output_mesh_file=tmp_folder / fs::path("output_mesh.med");
+ fs::path shape_file=tmp_folder / fs::path("shape.brep");
+ fs::path param_file=tmp_folder / fs::path("gmsh_param.txt");
+ fs::path log_file=tmp_folder / fs::path("run.log");
+ fs::path cmd_file=tmp_folder / fs::path("cmd.txt");
+
+ std::string mesh_name = "MESH";
+
+ {
+ SMESH_MeshLocker myLocker(&aMesh);
+ //Writing Shape
+ SMESH_DriverShape::exportShape(shape_file.string(), aShape);
+
+ //Writing hypothesis to file
+ exportGmshParams(param_file.string(), _hypothesis);
+
+ // Exporting element orientation
+ exportElementOrientation(aMesh, aShape, element_orientation_file.string());
+ }
+
+ // Calling run_mesher
+ // Path to mesher script
+ fs::path mesher_launcher = fs::path(std::getenv("SMESH_ROOT_DIR"))/
+ fs::path("bin")/
+ fs::path("salome")/
+ fs::path("mesher_launcher.py");
+
+ std::string s_program="python3";
+ std::list<std::string> params;
+ params.push_back(mesher_launcher.string());
+ params.push_back("GMSH3D");
+ params.push_back(mesh_file.string());
+ params.push_back(shape_file.string());
+ params.push_back(param_file.string());
+ params.push_back("--elem-orient-file=" + element_orientation_file.string());
+ params.push_back("--new-element-file=" + new_element_file.string());
+ // params.push_back("--output-mesh-file=" + output_mesh_file.string());
+
+ // Parallelism method parameters
+ int method = aParMesh.GetParallelismMethod();
+ if(method == ParallelismMethod::MultiThread){
+ params.push_back("--method=local");
+ } else if (method == ParallelismMethod::MultiNode){
+ params.push_back("--method=cluster");
+ params.push_back("--resource="+aParMesh.GetResource());
+ params.push_back("--wc-key="+aParMesh.GetWcKey());
+ params.push_back("--nb-proc=1");
+ params.push_back("--nb-proc-per-node="+std::to_string(aParMesh.GetNbProcPerNode()));
+ params.push_back("--nb-node="+std::to_string(aParMesh.GetNbNode()));
+ params.push_back("--walltime="+aParMesh.GetWalltime());
+ } else {
+ throw SALOME_Exception("Unknown parallelism method "+method);
+ }
+
+ std::string cmd = "";
+ cmd += s_program;
+ for(auto arg: params){
+ cmd += " " + arg;
+ }
+ MESSAGE("Running command: ");
+ MESSAGE(cmd);
+ // Writing command in cmd.log
+ {
+ std::ofstream flog(cmd_file.string());
+ flog << cmd << endl;
+ }
+
+ // Building arguments for QProcess
+ QString program = QString::fromStdString(s_program);
+ QStringList arguments;
+ for(auto arg : params){
+ arguments << arg.c_str();
+ }
+
+ QString out_file = log_file.string().c_str();
+ QProcess myProcess;
+ // myProcess.setProcessChannelMode(QProcess::MergedChannels);
+ myProcess.setProcessChannelMode(QProcess::ForwardedChannels);
+ myProcess.setStandardOutputFile(out_file);
+
+ myProcess.start(program, arguments);
+ // Waiting for process to finish (argument -1 make it wait until the end of
+ // the process otherwise it just waits 30 seconds)
+ bool finished = myProcess.waitForFinished(-1);
+ int ret = myProcess.exitCode();
+ if(ret != 0 || !finished){
+ // Run crahed
+ std::string msg = "Issue with mesh_launcher: \n";
+ msg += "See log for more details: " + log_file.string() + "\n";
+ msg += cmd + "\n";
+ throw SALOME_Exception(msg);
+ }
+ {
+ SMESH_MeshLocker myLocker(&aMesh);
+ // Binary file written from SA version of the mesher
+ std::ifstream df(new_element_file.string(), ios::binary);
+
+ int numberOfNodes;
+ int totalNumberOfNodes;
+ int numberOfVolumes;
+ double meshNodes[3];
+ int volNodes[4];
+ int nodeID;
+
+ SMESH_MesherHelper helper(aMesh);
+ // This function is mandatory for setElementsOnShape to work
+ helper.IsQuadraticSubMesh(aShape);
+ helper.SetElementsOnShape( true );
+
+ // Number of nodes in intial mesh
+ df.read((char*) &numberOfNodes, sizeof(int));
+ // Number of nodes added by netgen
+ df.read((char*) &totalNumberOfNodes, sizeof(int));
+ // Filling nodevec (correspondence netgen numbering mesh numbering)
+ std::vector< const SMDS_MeshNode* > nodeVec ( totalNumberOfNodes + 1 );
+ SMESHDS_Mesh * meshDS = helper.GetMeshDS();
+ for (int nodeIndex = 1 ; nodeIndex <= numberOfNodes; ++nodeIndex )
+ {
+ //Id of the point
+ df.read((char*) &nodeID, sizeof(int));
+ nodeVec.at(nodeIndex) = meshDS->FindNode(nodeID);
+ }
+
+ // Add new points and update nodeVec
+ for (int nodeIndex = numberOfNodes +1; nodeIndex <= totalNumberOfNodes; ++nodeIndex )
+ {
+ df.read((char *) &meshNodes, sizeof(double)*3);
+ nodeVec.at(nodeIndex) = helper.AddNode(meshNodes[0], meshNodes[1], meshNodes[2]);
+ }
+
+ // Add tetrahedrons
+ df.read((char*) &numberOfVolumes, sizeof(int));
+ for ( int elemIndex = 1; elemIndex <= numberOfVolumes; ++elemIndex )
+ {
+ df.read((char*) &volNodes, sizeof(int)*4);
+ auto n0 = meshDS->FindNode(nodeVec[volNodes[0]]->GetID());
+ auto n1 = meshDS->FindNode(nodeVec[volNodes[1]]->GetID());
+ auto n2 = meshDS->FindNode(nodeVec[volNodes[2]]->GetID());
+ auto n3 = meshDS->FindNode(nodeVec[volNodes[3]]->GetID());
+ if ( n0 && n1 && n2 && n3 )
+ helper.AddVolume( n0, n2, n1, n3 );
+ }
+ }
+
+ return true;
+}
+
+/**
+ * @brief Assign submeshes to compute
+ *
+ * @param aSubMesh submesh to add
+ */
+void GMSHPlugin_GMSH_3D_Remote::setSubMeshesToCompute(SMESH_subMesh * aSubMesh)
+{
+ SMESH_MeshLocker myLocker(aSubMesh->GetFather());
+ SMESH_Algo::setSubMeshesToCompute(aSubMesh);
+}
--- /dev/null
+// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+//=============================================================================
+// File : GMSHPlugin_GMSH_3D_Remote.hxx
+// Created : 09 Septembre 2023
+// Author : Cesar Conopoima (OCC)
+// Project : SALOME
+//=============================================================================
+//
+#ifndef _GMSHPlugin_GMSH_3D_REMOTE_HXX_
+#define _GMSHPlugin_GMSH_3D_REMOTE_HXX_
+
+#include "GMSHPlugin_GMSH_3D.hxx"
+
+#include <vector>
+#include <map>
+
+class SMDS_MeshNode;
+
+class GMSHPLUGIN_EXPORT GMSHPlugin_GMSH_3D_Remote: public GMSHPlugin_GMSH_3D
+{
+ public:
+ GMSHPlugin_GMSH_3D_Remote(int hypId, SMESH_Gen* gen);
+ virtual ~GMSHPlugin_GMSH_3D_Remote();
+
+ // Function whould not be used with remote Computing
+ bool CheckHypothesis (SMESH_Mesh& aMesh,
+ const TopoDS_Shape& aShape,
+ Hypothesis_Status& aStatus) override {(void)aMesh;(void)aShape;aStatus = HYP_OK;return true;};
+
+ bool Compute(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape) override;
+
+ void setSubMeshesToCompute(SMESH_subMesh * aSubMesh) override;
+
+
+ protected:
+ void exportElementOrientation(SMESH_Mesh& aMesh, const TopoDS_Shape& aShape, const std::string output_file);
+ void exportGmshParams( const std::string param_file, const SMESHDS_Hypothesis* hyp );
+ typedef std::set<std::string> TCompound;
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SMESH SMESH_I : idl implementation based on 'SMESH' unit's classes
+// File : GMSHPlugin_GMSH_3D_Remote_i.cxx
+// Author : Cesar Conopoima (OCC)
+// Module : GMSHPlugin
+// $Header$
+//
+#include "GMSHPlugin_GMSH_3D_Remote_i.hxx"
+#include "SMESH_Gen.hxx"
+
+#include "Utils_CorbaException.hxx"
+#include "utilities.h"
+
+//=============================================================================
+/*!
+ * GMSHPlugin_GMSH_3D_Remote_i::GMSHPlugin_GMSH_3D_Remote_i
+ *
+ * Constructor
+ */
+//=============================================================================
+
+GMSHPlugin_GMSH_3D_Remote_i::GMSHPlugin_GMSH_3D_Remote_i( PortableServer::POA_ptr thePOA,
+ ::SMESH_Gen* theGenImpl )
+ : SALOME::GenericObj_i( thePOA ),
+ SMESH_Hypothesis_i( thePOA ),
+ SMESH_Algo_i( thePOA ),
+ SMESH_3D_Algo_i( thePOA )
+{
+ myBaseImpl = new ::GMSHPlugin_GMSH_3D_Remote( theGenImpl->GetANewId(),
+ theGenImpl );
+}
+
+//=============================================================================
+/*!
+ * GMSHPlugin_GMSH_3D_Remote_i::~GMSHPlugin_GMSH_3D_Remote_i
+ *
+ * Destructor
+ */
+//=============================================================================
+
+GMSHPlugin_GMSH_3D_Remote_i::~GMSHPlugin_GMSH_3D_Remote_i()
+{
+}
+
+//=============================================================================
+/*!
+ * GMSHPlugin_GMSH_3D_Remote_i::GetImpl
+ *
+ * Get implementation
+ */
+//=============================================================================
+
+::GMSHPlugin_GMSH_3D_Remote* GMSHPlugin_GMSH_3D_Remote_i::GetImpl()
+{
+ return ( ::GMSHPlugin_GMSH_3D_Remote* )myBaseImpl;
+}
+
--- /dev/null
+// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// SMESH SMESH_I : idl implementation based on 'SMESH' unit's classes
+// File : GMSHPlugin_GMSH_3D_Remote_i.hxx
+// Author : Cesar Conopoima (OCC)
+// Module : GMSHPlugin
+// $Header$
+//
+#ifndef _GMSHPlugin_GMSH_3D_REMOTE_I_HXX_
+#define _GMSHPlugin_GMSH_3D_REMOTE_I_HXX_
+
+#include "GMSHPlugin_Defs.hxx"
+
+#include <SALOMEconfig.h>
+#include CORBA_SERVER_HEADER(GMSHPlugin_Algorithm)
+
+#include "SMESH_3D_Algo_i.hxx"
+#include "GMSHPlugin_GMSH_3D_Remote.hxx"
+
+// ======================================================
+// GMSH 3d algorithm
+// ======================================================
+class GMSHPLUGIN_EXPORT GMSHPlugin_GMSH_3D_Remote_i:
+ public virtual POA_GMSHPlugin::GMSHPlugin_GMSH_3D_Remote,
+ public virtual SMESH_3D_Algo_i
+{
+public:
+ // Constructor
+ GMSHPlugin_GMSH_3D_Remote_i( PortableServer::POA_ptr thePOA,
+ ::SMESH_Gen* theGenImpl );
+ // Destructor
+ virtual ~GMSHPlugin_GMSH_3D_Remote_i();
+
+ // Get implementation
+ ::GMSHPlugin_GMSH_3D_Remote* GetImpl();
+};
+
+#endif
--- /dev/null
+// Copyright (C) 2012-2015 ALNEOS
+// Copyright (C) 2016-2023 EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.alneos.com/ or email : contact@alneos.fr
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#include "GMSHPlugin_GMSH_3D.hxx"
+#include "GMSHPlugin_GMSH_3D_SA.hxx"
+#include "GMSHPlugin_Hypothesis_2D.hxx"
+#include "GMSHPlugin_Mesher.hxx"
+
+#include <SMESH_Gen.hxx>
+#include <SMESH_ControlsDef.hxx>
+#include <SMESHDS_Mesh.hxx>
+#include <utilities.h>
+
+#include <list>
+
+//=============================================================================
+/*!
+ *
+ */
+//=============================================================================
+
+GMSHPlugin_GMSH_3D_SA::GMSHPlugin_GMSH_3D_SA()
+ : GMSHPlugin_GMSH_3D(0, new SMESH_Gen() )
+{
+ MESSAGE("GMSHPlugin_GMSH_3D_SA::GMSHPlugin_GMSH_3D_SA");
+ _name = "GMSH_3D_SA";
+}
+
+//=============================================================================
+/*!
+ *
+ */
+//=============================================================================
+
+GMSHPlugin_GMSH_3D_SA::~GMSHPlugin_GMSH_3D_SA()
+{
+ MESSAGE("GMSHPlugin_GMSH_3D_SA::~GMSHPlugin_GMSH_3D_SA");
+}
+
+void GMSHPlugin_GMSH_3D_SA::importGMSHParameters( const std::string hypo_file )
+{
+ GMSHPlugin_Hypothesis * hypParameters = new GMSHPlugin_Hypothesis(0, GetGen());
+ std::ifstream myfile(hypo_file);
+ std::string line;
+
+ std::getline(myfile, line);
+ int hasParams = std::stoi(line);
+ if ( hasParams )
+ {
+ std::getline(myfile, line);
+ hypParameters->Set2DAlgo( (GMSHPlugin_Hypothesis::Algo2D)(std::stoi(line)) );
+ std::getline(myfile, line);
+ hypParameters->Set3DAlgo( (GMSHPlugin_Hypothesis::Algo3D)(std::stoi(line)) );
+ std::getline(myfile, line);
+ hypParameters->SetRecomb2DAlgo( (GMSHPlugin_Hypothesis::Recomb2DAlgo)(std::stoi(line)) );
+ std::getline(myfile, line);
+ hypParameters->SetRecombineAll( std::stoi(line) );
+ std::getline(myfile, line);
+ hypParameters->SetSubdivAlgo( (GMSHPlugin_Hypothesis::SubdivAlgo)(std::stoi(line)) );
+ std::getline(myfile, line);
+ hypParameters->SetRemeshAlgo( (GMSHPlugin_Hypothesis::RemeshAlgo)(std::stoi(line)) );
+ std::getline(myfile, line);
+ hypParameters->SetSmouthSteps( std::stod(line) );
+ std::getline(myfile, line);
+ hypParameters->SetSizeFactor( std::stod(line) );
+ std::getline(myfile, line);
+#if GMSH_MAJOR_VERSION >=4 && GMSH_MINOR_VERSION >=10
+ hypParameters->SetMeshCurvatureSize( std::stod(line) );
+#endif
+ std::getline(myfile, line);
+ hypParameters->SetMaxSize( std::stod(line) );
+ std::getline(myfile, line);
+ hypParameters->SetMinSize( std::stod(line) );
+ std::getline(myfile, line);
+ hypParameters->SetSecondOrder( std::stoi(line) );
+ std::getline(myfile, line);
+ hypParameters->SetUseIncomplElem( std::stoi(line) );
+ std::getline(myfile, line); // Get Compound names comma separated
+ if ( line != "0" ) // Mark no presence of groups
+ {
+ std::stringstream compoundLine (line);
+ std::string compound;
+ while ( std::getline (compoundLine, compound, ',') )
+ hypParameters->SetCompoundOnEntry( compound );
+ }
+ _hypothesis = dynamic_cast< const GMSHPlugin_Hypothesis *> (hypParameters);
+ }
+ else
+ {
+ // in case the parameters are not defined the _hypothesis should remain undefined
+ // so default parameters are used to mesh!
+ // _hypothesis = NULL;
+ }
+}
+
+/**
+ * @brief Write a binary file containing information on the elements/nodes
+ * created by the mesher
+ *
+ * @param nodeVec mapping between the mesh id and the netgen structure id
+ * @param mesher gmhsplugin mesher
+ * @param new_element_file Name of the output file
+ * @return true if there are some error
+ */
+void GMSHPlugin_GMSH_3D_SA::fillNewElementFile( std::vector< const SMDS_MeshNode* > &nodeVec, GMSHPlugin_Mesher &mesher, std::string new_element_file )
+{
+ GModel* gModel = mesher.GetGModel();
+ const int numberOfNodes = nodeVec.size() - 1;
+ const int numOfVolumens = gModel->getNumMeshElements( 3 );
+ int numberOfTotalNodes = numberOfNodes;
+ std::map< MVertex *,int> nodeMap;
+ bool isOK = ( numOfVolumens > 0 );
+ if ( isOK && !new_element_file.empty() )
+ {
+ MESSAGE("Writting new elements");
+
+ std::ofstream df(new_element_file, ios::out|ios::binary);
+ double points[3];
+ int volumens[4];
+
+ df.write((char*) &numberOfNodes, sizeof(int));
+
+ // To get 3D elements we need to iterate in regions
+ std::map<int,MVertex*> vertexIdToCoordinate;
+ // Index nodes of new volumetric elements in order from the vol region
+ for ( GModel::riter it = gModel->firstRegion(); it != gModel->lastRegion(); ++it)
+ {
+ GRegion *gRegion = *it;
+ for( size_t i = 0; i < gRegion->mesh_vertices.size(); i++)
+ {
+ MVertex *v = gRegion->mesh_vertices[i];
+ const SMDS_MeshNode * preMeshedNode = mesher.PremeshedNode( v );
+ if ( !preMeshedNode )
+ {
+ numberOfTotalNodes++;
+ vertexIdToCoordinate[ numberOfTotalNodes ] = v;
+ nodeMap.insert({ v, numberOfTotalNodes });
+ }
+ }
+ }
+
+ df.write((char*) &numberOfTotalNodes, sizeof(int));
+
+ for (int nodeIndex = 1 ; nodeIndex <= numberOfNodes; ++nodeIndex )
+ {
+ //Id of the point
+ int id = nodeVec.at(nodeIndex)->GetID();
+ df.write((char*) &id, sizeof(int));
+ }
+
+ // Writing info on new points
+ for (int nodeIndex = numberOfNodes+1; nodeIndex <= numberOfTotalNodes; ++nodeIndex )
+ {
+ if ( vertexIdToCoordinate[nodeIndex] )
+ {
+ df.write((char *) &vertexIdToCoordinate[nodeIndex]->x(), sizeof(double) );
+ df.write((char *) &vertexIdToCoordinate[nodeIndex]->y(), sizeof(double) );
+ df.write((char *) &vertexIdToCoordinate[nodeIndex]->z(), sizeof(double) );
+ }
+ }
+
+ df.write((char*) &numOfVolumens, sizeof(int));
+ for ( GModel::riter it = gModel->firstRegion(); it != gModel->lastRegion(); ++it)
+ {
+ GRegion *gRegion = *it;
+ std::vector<MVertex*> verts;
+
+ for( size_t i = 0; i < gRegion->getNumMeshElements(); i++)
+ {
+ MElement *element = gRegion->getMeshElement(i);
+ verts.clear();
+ element->getVertices(verts);
+ for( MVertex* v : verts )
+ {
+ const SMDS_MeshNode * node = mesher.PremeshedNode( v );
+ auto it = find(nodeVec.begin(), nodeVec.end(), node );
+ int nodeId = node ? (it - nodeVec.begin()) : nodeMap[ v ];
+ df.write((char*) &nodeId, sizeof(int) );
+ }
+ }
+ }
+ df.close();
+ }
+}
+
+/**
+ * @brief Fill the list of elements in order and associate the read orientation (if any) to then.
+ * Index the elements and orientation to the ordered map so we are sure the write orientation
+ * match the element from the load mesh. IF no orientation file was written, then all the faces
+ * of the read mesh match the face orientation of his original associated face
+ * @param aMesh the loaded mesh
+ * @param element_orientation_file name of the file where to read the orientation
+ * @param listElements the ordered map of elements with his orientation associated
+ * @return the listElements filled.
+ */
+void GMSHPlugin_GMSH_3D_SA::fillListOfElementsOriented( SMESH_Mesh& aMesh, std::string element_orientation_file,
+ std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements )
+{
+
+ // fill the elements found in the surface to the listOfElements so it can be used by the mesher!
+ SMESHDS_Mesh* meshDS = aMesh.GetMeshDS();
+ std::map<vtkIdType, bool> elemOrientation;
+ {
+ // Setting all element orientation to false if there no element orientation file
+ if(element_orientation_file.empty())
+ {
+ SMDS_ElemIteratorPtr iteratorElem = meshDS->elementsIterator(SMDSAbs_Face);
+ while ( iteratorElem->more() ) // loop on elements on a geom face
+ {
+ // check mesh face
+ const SMDS_MeshElement* elem = iteratorElem->next();
+ listElements[elem] = false;
+ }
+ }
+ else
+ {
+ std::ifstream df(element_orientation_file, ios::binary|ios::in);
+ int nbElement;
+ bool orient;
+
+ vtkIdType id;
+ df.read((char*)&nbElement, sizeof(int));
+
+ for(int ielem=0;ielem<nbElement;++ielem){
+ df.read((char*) &id, sizeof(vtkIdType));
+ df.read((char*) &orient, sizeof(bool));
+ elemOrientation[id] = orient;
+ }
+ df.close();
+ //
+ SMDS_ElemIteratorPtr iteratorElem = meshDS->elementsIterator(SMDSAbs_Face);
+ while ( iteratorElem->more() ) // loop on elements on a geom face
+ {
+ // check mesh face
+ const SMDS_MeshElement* elem = iteratorElem->next();
+ // only index registered elements
+ bool isIn = elemOrientation.count(elem->GetID())==1;
+ if(!isIn) continue;
+ listElements[elem] = elemOrientation[elem->GetID()];
+ }
+ }
+ }
+}
+
+
+/**
+ * @brief Compute the mesh by first filling premeshed faces to gmsh and then calling the mesher for the upper dimension
+ * @param aShape the loaded shape
+ * @param aMesh the read Mesh (contain 2D elements covering the entire geometry)
+ * @param new_element_file output file containing info the elements created by the mesher
+ * @param element_orientation_file Binary file containing the orientation of surface elemnts
+ * @param output_mesh whether or not write the created elements into the mesh
+ * @return negation of mesh fail: true, false
+ * */
+bool GMSHPlugin_GMSH_3D_SA::Compute( TopoDS_Shape &aShape, SMESH_Mesh& aMesh, std::string new_element_file,
+ std::string element_orientation_file, bool output_mesh )
+{
+ GMSHPlugin_Mesher mesher(&aMesh, aShape,/*2d=*/false, true);
+ std::vector< const SMDS_MeshNode* > nodeVec; // to save premeshed elements
+ mesher.SetParameters(dynamic_cast<const GMSHPlugin_Hypothesis*>(_hypothesis));
+
+ std::map<const SMDS_MeshElement*, bool, TIDCompare> listElements;
+ fillListOfElementsOriented( aMesh, element_orientation_file, listElements );
+ bool Compute = mesher.Compute3D( nodeVec, listElements, output_mesh );
+
+ fillNewElementFile( nodeVec, mesher, new_element_file );
+ mesher.finalizeGModel();
+ return Compute;
+}
+
+/**
+ * @brief Running the mesher on the given files
+ *
+ * @param input_mesh_file Mesh file (containing 2D elements)
+ * @param shape_file Shape file (BREP or STEP format)
+ * @param hypo_file Ascii file containing the gmsh parameters
+ * @param element_orientation_file Binary file containing the orientation of surface elements
+ * @param new_element_file output file containing info the elements created by the mesher
+ * @param output_mesh_file output mesh file (if empty it will not be created)
+ * @return int
+ */
+int GMSHPlugin_GMSH_3D_SA::run(const std::string input_mesh_file,
+ const std::string shape_file,
+ const std::string hypo_file,
+ const std::string element_orientation_file,
+ const std::string new_element_file,
+ const std::string output_mesh_file)
+{
+ std::unique_ptr<SMESH_Mesh> myMesh(_gen->CreateMesh(false));
+
+ SMESH_DriverMesh::importMesh(input_mesh_file, *myMesh);
+
+ // Importing shape
+ TopoDS_Shape myShape;
+ SMESH_DriverShape::importShape(shape_file, myShape);
+
+ // Define _hypothesis to then be able to call SetParameters( hypothesis )
+ importGMSHParameters(hypo_file);
+
+ MESSAGE("Meshing with gmsh3d");
+ int ret = Compute(myShape, *myMesh, new_element_file, element_orientation_file, !output_mesh_file.empty());
+
+ if(ret){
+ std::cerr << "Meshing failed" << std::endl;
+ return ret;
+ }
+
+ if(!output_mesh_file.empty()){
+ std::string meshName = "MESH";
+ SMESH_DriverMesh::exportMesh(output_mesh_file, *myMesh, meshName);
+ }
+
+ return ret;
+}
\ No newline at end of file
--- /dev/null
+// Copyright (C) 2012-2015 ALNEOS
+// Copyright (C) 2016-2023 EDF
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.alneos.com/ or email : contact@alneos.fr
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+#ifndef _GMSHPlugin_GMSH_3D_SA_HXX_
+#define _GMSHPlugin_GMSH_3D_SA_HXX_
+
+#include "GMSHPlugin_Defs.hxx"
+#include "GMSHPlugin_GMSH_3D.hxx"
+
+#include <SMESH_DriverShape.hxx>
+#include <SMESH_DriverMesh.hxx>
+
+#include "SMESH_Algo.hxx"
+#include "SMESH_subMesh.hxx"
+#include "SMESH_Mesh.hxx"
+
+class GMSHPLUGIN_EXPORT GMSHPlugin_GMSH_3D_SA: public GMSHPlugin_GMSH_3D
+{
+public:
+ GMSHPlugin_GMSH_3D_SA();
+ virtual ~GMSHPlugin_GMSH_3D_SA();
+
+ int run(const std::string input_mesh_file,
+ const std::string shape_file,
+ const std::string hypo_file,
+ const std::string element_orientation_file,
+ const std::string new_element_file,
+ const std::string output_mesh_file);
+
+ bool Compute( TopoDS_Shape &aShape, SMESH_Mesh& aMesh, std::string new_element_file, std::string element_orientation_file, bool output_mesh );
+
+private:
+
+ void fillNewElementFile( std::vector< const SMDS_MeshNode* > &nodeVec, GMSHPlugin_Mesher &mesher, std::string new_element_file );
+ void importGMSHParameters( const std::string hypo_file );
+ void fillListOfElementsOriented(SMESH_Mesh& aMesh, std::string element_orientation_file,
+ std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements );
+};
+
+#endif
#include <vector>
#include <limits>
+#include <TopExp.hxx>
#include <TopExp_Explorer.hxx>
#include <TopoDS.hxx>
}
#endif
+
+//================================================================================
+/*!
+ * \brief Check that the passed nodes are all IN the face
+ * \param element the element
+ * \param F the geom Face
+ * \param uvValues a vector of size elem->NbCornerNodes() to save the uv coordinate points on the face
+ * \return true if all the nodes are IN the face
+ */
+ //================================================================================
+bool GMSHPlugin_Mesher::IsAllNodesInSameFace( const SMDS_MeshElement* element, const TopoDS_Face& F,
+ std::vector<gp_XY>& uvValues )
+{
+ Handle(ShapeAnalysis_Surface) sprojector = new ShapeAnalysis_Surface( BRep_Tool::Surface( F ));
+ double tol = BRep_Tool::MaxTolerance( F, TopAbs_FACE );
+ int nbN = element->NbCornerNodes();
+ gp_Pnt surfPnt(0,0,0);
+ for ( int i = 0; i < nbN; ++i )
+ {
+ SMESH_NodeXYZ nXYZ( element->GetNode( i ) );
+ gp_XY uv = sprojector->ValueOfUV( nXYZ, tol ).XY();
+ surfPnt = sprojector->Value( uv );
+ double dist = surfPnt.Distance( nXYZ );
+ if ( dist > tol )
+ return false;
+ else
+ uvValues[ i ] = uv;
+ }
+ return true;
+}
+
+//================================================================================
+/*!
+ * \brief Associate mesh elements to geometrical faces.
+ * \param the list of elements
+ * \return a map between faces (incremental order) and mesh elements found to be placed on the face
+ */
+ //================================================================================
+std::map<int,std::vector<std::tuple<smIdType,bool,std::vector<gp_XY>>>> GMSHPlugin_Mesher::AssociateElementsToFaces( std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements )
+{
+ // Map faces to elementId and uv of nodes.
+ // Index by face id
+ // Index vector with element smIdType, [ gp_XY_0, gp_XY_1, gp_XY_2 ]
+ std::map<int,std::vector<std::tuple<smIdType,bool,std::vector<gp_XY>>>> elementToFaceMap;
+ SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
+ SMDS_ElemIteratorPtr iteratorElem = meshDS->elementsIterator(SMDSAbs_Face);
+ for ( auto const& [elem, IsReverse] : listElements ) // loop on elements on a geom face
+ {
+ int nbN = elem->NbCornerNodes();
+ std::vector<gp_XY> uvValues(nbN);
+ if ( nbN > 4 /*this restriction might be eliminated. Have to adapt FillGeomMapMeshUsing2DMeshIterator function too */)
+ throw std::string("Polygon sub-meshes not supported");
+
+ int faceId = 1;
+ for( GModel::fiter it = _gModel->firstFace(); it != _gModel->lastFace(); ++it )
+ {
+ GFace *gFace = *it;
+ TopoDS_Face topoFace = *((TopoDS_Face*)gFace->getNativePtr());
+ if ( IsAllNodesInSameFace( elem, topoFace, uvValues ) )
+ {
+ elementToFaceMap[ faceId ].push_back( std::make_tuple( elem->GetID(), IsReverse, uvValues ) );
+ break;
+ }
+ faceId++;
+ }
+ }
+ return elementToFaceMap;
+}
+
+//================================================================================
+/*!
+ * \brief Add the elements found associated to the face as gmsh elements
+ */
+ //================================================================================
+void GMSHPlugin_Mesher::Set2DMeshes( std::vector< const SMDS_MeshNode* >& nodeVec, std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements )
+{
+ std::map< const SMDS_MeshNode* , const MVertex * > nodes2mvertMap;
+ SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
+ auto elementToFaceMap = AssociateElementsToFaces( listElements );
+ int faceId = 1;
+ std::vector<MVertex *> mVertices;
+
+ for(GModel::fiter it = _gModel->firstFace(); it != _gModel->lastFace(); ++it)
+ {
+ GFace *gFace = *it;
+ gFace->deleteMesh();
+
+ auto element2uv = elementToFaceMap.find( faceId )->second;
+
+ const int numberOfEntries = element2uv.size();
+
+ for (int el = 0; el < numberOfEntries; el++)
+ {
+ const smIdType elementId = std::get<0>( element2uv[ el ] ); // smesh element id
+ bool isReverse = std::get<1>( element2uv[ el ] );
+ const SMDS_MeshElement* elem = meshDS->FindElement( elementId );
+
+ int nbN = elem->NbCornerNodes();
+ mVertices.resize( nbN );
+
+ for ( int i = 0; i < nbN; ++i )
+ {
+ const SMDS_MeshNode* n = elem->GetNode( i );
+ MVertex * mv = nullptr;
+ auto n2v = nodes2mvertMap.find( n );
+ if ( n2v != nodes2mvertMap.end() )
+ {
+ mv = const_cast< MVertex*>( n2v->second );
+ }
+ else
+ {
+ if ( n->GetPosition()->GetDim() < 2 )
+ throw std::string("Wrong mapping of edge nodes to GMSH nodes");
+ SMESH_NodeXYZ xyz = n;
+ gp_XY uv = std::get<2>(element2uv[ el ])[ i ];
+ mv = new MFaceVertex( xyz.X(), xyz.Y(), xyz.Z(), gFace, uv.X(), uv.Y() );
+ gFace->mesh_vertices.push_back( mv );
+ nodes2mvertMap.insert({ n, mv });
+ _nodeMap.insert ({ mv, n });
+ _premeshednodeMap.insert({ mv, n });
+ }
+ mVertices[ i ] = mv;
+ }
+ // create GMSH mesh faces
+ switch ( nbN ) {
+ case 3:
+ if ( isReverse )
+ gFace->triangles.push_back (new MTriangle(mVertices[0], mVertices[2], mVertices[1]));
+ else
+ gFace->triangles.push_back (new MTriangle(mVertices[0], mVertices[1], mVertices[2]));
+ break;
+ case 4:
+ if ( isReverse )
+ gFace->quadrangles.push_back (new MQuadrangle(mVertices[0], mVertices[3],
+ mVertices[2], mVertices[1]));
+ else
+ gFace->quadrangles.push_back (new MQuadrangle(mVertices[0], mVertices[1],
+ mVertices[2], mVertices[3]));
+ break;
+ default:;
+ }
+ }
+ faceId++; // face counter
+ } // iterator in the face
+
+ // Fill the node
+ nodeVec.resize( nodes2mvertMap.size() + 1, 0 );
+ int count = 1;
+ for (auto k : nodes2mvertMap )
+ {
+ nodeVec[ count ] = k.first; // Index the node id to the smesh node itself
+ count++;
+ }
+}
+
+
+//================================================================================
+/*!
+ * \brief Initialize GMSH model with mesh elements as geometry objects.
+ * Nodes are vertexes and element connections are geom lines
+ */
+ //================================================================================
+void GMSHPlugin_Mesher::FillGeomMapMeshUsing2DMeshIterator( std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements )
+{
+ gmsh::initialize();
+ gmsh::model::add("mesh");
+ // typedef for maps
+ typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap;
+ typedef TNodeToIDMap::value_type TN2ID;
+ typedef map<std::pair<int, int>, int> TLineToIDMap;
+ TNodeToIDMap aNodeToID;
+ TLineToIDMap aLineToID;
+
+ int aNbOfNodes = 0;
+ int aNbOfLines = 0;
+
+ const int invalid_ID = -1;
+ std::vector<int> aTrinagle( 3, 0 );
+
+ // Playing around with SMESHDS_Mesh structure
+ SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
+
+ for ( auto const& [elem, IsReverse] : listElements ) // loop on elements on a geom face
+ {
+ if ( elem->NbCornerNodes() != 3 )
+ return;
+
+ for (int iN = 0; iN < 3; ++iN)
+ {
+ const SMDS_MeshNode* aNode = elem->GetNode(iN);
+
+ int& ngID = aNodeToID.insert(TN2ID(aNode, invalid_ID)).first->second;
+ if (ngID == invalid_ID)
+ {
+ ngID = ++aNbOfNodes;
+ gmsh::model::occ::addPoint(aNode->X(), aNode->Y(), aNode->Z(), 1.e-2, ngID);
+ }
+
+ aTrinagle[ IsReverse ? 2 - iN : iN ] = ngID;
+ }
+ // add triangle
+ if ((aTrinagle[0] == aTrinagle[1] ||
+ aTrinagle[0] == aTrinagle[2] ||
+ aTrinagle[2] == aTrinagle[1]))
+ continue;
+
+ std::vector<int> LinesID(3, 0);
+ for (int anIndex = 0; anIndex < 3; ++anIndex)
+ {
+ int aNextIndex = (anIndex + 1) % 3;
+ if (aLineToID.find({ aTrinagle[anIndex], aTrinagle[aNextIndex] }) == aLineToID.end()
+ && aLineToID.find({ aTrinagle[aNextIndex], aTrinagle[anIndex] }) == aLineToID.end())
+ {
+ LinesID[anIndex] = aLineToID.insert({ { aTrinagle[aNextIndex], aTrinagle[anIndex] }, ++aNbOfLines }).first->second;
+ gmsh::model::occ::addLine(aTrinagle[anIndex], aTrinagle[aNextIndex], LinesID[anIndex]);
+ }
+ else
+ {
+ LinesID[anIndex] = aLineToID.find({ aTrinagle[anIndex], aTrinagle[aNextIndex] })->second;
+ if (LinesID[anIndex] == 0)
+ LinesID[anIndex] = aLineToID.find({ aTrinagle[aNextIndex], aTrinagle[anIndex] })->second;
+
+ }
+ }
+ // if (!aProxyMesh->IsTemporary(ls.first))
+ // swap(aTrinagle[1], aTrinagle[2]);
+ gmsh::model::occ::addCurveLoop(LinesID);
+ }
+}
+
//================================================================================
/*!
* \brief Initialize GMSH model
SMESHDS_Mesh* meshDS = _mesh->GetMeshDS();
int aNbOfNodes = 0;
- int aNbOfCurves = 0;
int aNbOfLines = 0;
std::vector<int> aTrinagle(3, 0);
{
const TopoDS_Shape& aShapeFace = exFa.Current();
int faceID = meshDS->ShapeToIndex(aShapeFace);
-
bool isRev = false;
if (aCheckReverse && aHelper.NbAncestors(aShapeFace, *_mesh, _shape.ShapeType()) > 1)
// IsReversedSubMesh() can work wrong on strongly curved faces,
isRev = aHelper.IsReversedSubMesh(TopoDS::Face(aShapeFace));
const SMESHDS_SubMesh* aSubMeshDSFace = aProxyMesh->GetSubMesh(aShapeFace);
- if (!aSubMeshDSFace) continue;
-
+ if (!aSubMeshDSFace)
+ continue;
SMDS_ElemIteratorPtr iteratorElem = aSubMeshDSFace->GetElements();
if (aHelper.IsQuadraticSubMesh(_shape) &&
dynamic_cast<const SMESH_ProxyMesh::SubMesh*>(aSubMeshDSFace))
// add triangle
if (hasDegen && (aTrinagle[0] == aTrinagle[1] ||
aTrinagle[0] == aTrinagle[2] ||
- aTrinagle[2] == aTrinagle[1]))
- continue;
+ aTrinagle[2] == aTrinagle[1]))
+ continue;
std::vector<int> LinesID(3, 0);
if (!aProxyMesh->IsTemporary(ls.first))
swap(aTrinagle[1], aTrinagle[2]);
- int aTag = gmsh::model::occ::addCurveLoop(LinesID);
+ gmsh::model::occ::addCurveLoop(LinesID);
}
// Generate 1D and 2D mesh
return nullptr;
}
+//================================================================================
+/*!
+ * \brief Get a node by a GMSH mesh vertex
+ */
+//================================================================================
+
+const SMDS_MeshNode* GMSHPlugin_Mesher::PremeshedNode( const MVertex* v )
+{
+ std::map< const MVertex *, const SMDS_MeshNode* >::iterator v2n = _premeshednodeMap.find( v );
+ if ( v2n != _premeshednodeMap.end() )
+ return v2n->second;
+
+ return nullptr;
+}
+
+
//================================================================================
/*!
* \brief Return a corresponding sub-mesh if a shape is meshed
}
}
+bool GMSHPlugin_Mesher::Compute3D( std::vector< const SMDS_MeshNode* >& nodeVec, std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements, bool addElements )
+{
+ MESSAGE("GMSHPlugin_Mesher::Compute3D");
+ int err = 0;
+ _maxThreads = 1;
+#if GMSH_MAJOR_VERSION >=4 && GMSH_MINOR_VERSION >=3
+ _maxThreads = 1;
+#endif
+
+ char* argv[] = {"-noenv"};
+ GmshInitialize(1,argv);
+ SetGmshOptions();
+ _gModel = new GModel();
+ mymsg msg(_gModel);
+ GmshSetMessageHandler(&msg);
+
+ _gModel->importOCCShape((void*)&_shape);
+ try
+ {
+ HideComputedEntities( _gModel, true );
+ // fill geometry with elements as geom objects
+ FillGeomMapMeshUsing2DMeshIterator( listElements );
+ Set2DMeshes( nodeVec, listElements );
+ _gModel->mesh( /*dim=*/ 3);
+ }
+ catch (std::string& str)
+ {
+ err = 1;
+ MESSAGE(str);
+ }
+ catch (...)
+ {
+ err = 1;
+ MESSAGE("Unrecoverable error during Generation of Gmsh Mesh");
+ }
+
+ if (!err)
+ {
+#if GMSH_MAJOR_VERSION >=4 && GMSH_MINOR_VERSION >=8
+ if (_compounds.size() > 0)
+ SetCompoundMeshVisibility();
+#endif
+ }
+
+ if ( addElements )
+ FillSMesh();
+ MESSAGE("GMSHPlugin_Mesher::Compute3D:End");
+ return err;
+}
+
+void GMSHPlugin_Mesher::finalizeGModel()
+{
+ if ( _gModel )
+ {
+ GmshSetMessageHandler(nullptr);
+ delete _gModel;
+ GmshFinalize();
+ }
+}
+
//=============================================================================
/*!
* Here we are going to use the GMSH mesher
if (_is3d)
{
FillGMSHMesh();
-
Set2DSubMeshes(_gModel);
-
_gModel->mesh( /*dim=*/ 3);
}
else
{
//CTX::instance()->mesh.maxNumThreads1D=1;
-
_gModel->mesh( /*dim=*/ 1);
Set1DSubMeshes(_gModel);
*/
//================================================================================
-void GMSHPlugin_Mesher::HideComputedEntities( GModel* gModel )
+void GMSHPlugin_Mesher::HideComputedEntities( GModel* gModel, bool hideAnyway )
{
CTX::instance()->mesh.meshOnlyVisible = true;
continue;
TopoDS_Edge topoEdge = *((TopoDS_Edge*)gEdge->getNativePtr());
- if ( HasSubMesh( topoEdge ))
+ if ( HasSubMesh( topoEdge ) || hideAnyway )
gEdge->setVisibility(0);
}
continue;
TopoDS_Face topoFace = *((TopoDS_Face*)gFace->getNativePtr());
- if ( HasSubMesh( topoFace ))
+ if ( HasSubMesh( topoFace ) || hideAnyway )
gFace->setVisibility(0);
}
}
#endif
#include "MElement.h"
+#include <SMDS_MeshElement.hxx>
#include "GMSHPlugin_Defs.hxx"
#include "SMESH_Algo.hxx"
void SetParameters(const GMSHPlugin_Hypothesis* hyp);
+ bool Compute3D( std::vector< const SMDS_MeshNode* >& nodeVec,
+ std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements,
+ bool addElements );
bool Compute();
bool Evaluate(MapShapeNbElems& aResMap);
static float DistBoundingBox(const SBoundingBox3d& bounds, const SPoint3& point);
void FillGMSHMesh();
+ void FillGeomMapMeshUsing2DMeshIterator( std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements );
+ GModel* GetGModel(){ return _gModel;};
+ void finalizeGModel();
+ const SMDS_MeshNode* Node( const MVertex* v );
+ const SMDS_MeshNode* PremeshedNode( const MVertex* v );
private:
SMESH_Mesh* _mesh;
std::set<std::string> _compounds;
std::map< const MVertex *, const SMDS_MeshNode* > _nodeMap;
-
- const SMDS_MeshNode* Node( const MVertex* v );
+ std::map< const MVertex *, const SMDS_MeshNode* > _premeshednodeMap; // used for the SA version
SMESHDS_SubMesh* HasSubMesh( const TopoDS_Shape& s );
void SetGmshOptions();
void CreateGmshCompounds();
void FillSMesh();
- void HideComputedEntities( GModel* gModel );
+ void HideComputedEntities( GModel* gModel, bool hideAnyway = false );
void RestoreVisibility( GModel* gModel );
void Set1DSubMeshes( GModel* );
void Set2DSubMeshes( GModel* );
void toPython( GModel* );
+ bool IsAllNodesInSameFace( const SMDS_MeshElement* triangle, const TopoDS_Face& F, std::vector<gp_XY>& uvValues );
+ std::map<int,std::vector<std::tuple<smIdType,bool,std::vector<gp_XY>>>> AssociateElementsToFaces( std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements );
+ void Set2DMeshes( std::vector< const SMDS_MeshNode* >& nodeVec, std::map<const SMDS_MeshElement*, bool, TIDCompare>& listElements );
+
#if GMSH_MAJOR_VERSION >=4 && GMSH_MINOR_VERSION >=3
void SetMaxThreadsGmsh();
void SetCompoundMeshVisibility();
--- /dev/null
+// Copyright (C) 2007-2023 CEA, EDF, OPEN CASCADE
+//
+// Copyright (C) 2003-2007 OPEN CASCADE, EADS/CCR, LIP6, CEA/DEN,
+// CEDRAT, EDF R&D, LEG, PRINCIPIA R&D, BUREAU VERITAS
+//
+// This library is free software; you can redistribute it and/or
+// modify it under the terms of the GNU Lesser General Public
+// License as published by the Free Software Foundation; either
+// version 2.1 of the License, or (at your option) any later version.
+//
+// This library is distributed in the hope that it will be useful,
+// but WITHOUT ANY WARRANTY; without even the implied warranty of
+// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+// Lesser General Public License for more details.
+//
+// You should have received a copy of the GNU Lesser General Public
+// License along with this library; if not, write to the Free Software
+// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+//
+// See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com
+//
+
+// File : GMSHPlugin_Runner_main.cxx
+// Author : Cesar Conopoima, Open Cascade
+// Module : GMSH
+//
+
+#include "GMSHPlugin_GMSH_3D_SA.hxx"
+
+#include <stdio.h>
+#include <string.h>
+#include <iostream>
+#include <chrono>
+
+/**
+ * @brief Main function
+ *
+ * @param argc Number of arguments
+ * @param argv Arguments
+ *
+ * @return error code
+ */
+int main(int argc, char *argv[]){
+
+ if(argc!=8||(argc==2 && (strcmp(argv[1], "-h") == 0 || strcmp(argv[1], "--help")==0))){
+ std::cout << "Error in number of arguments "<< argc-1<<" given expected 7" <<std::endl;
+ std::cout << "Syntax:"<<std::endl;
+ std::cout << "run_mesher MESHER INPUT_MESH_FILE SHAPE_FILE HYPO_FILE" << std::endl;
+ std::cout << " ELEM_ORIENT_FILE " << std::endl;
+ std::cout << " NEW_ELEMENT_FILE OUTPUT_MESH_FILE" << std::endl;
+ std::cout << std::endl;
+ std::cout << " Set argument to NONE to ignore them " << std::endl;
+ std::cout << std::endl;
+ std::cout << "Args:" << std::endl;
+ std::cout << " MESHER: mesher to use from (NETGEN3D, NETGEN2D)" << std::endl;
+ std::cout << " INPUT_MESH_FILE: MED File containing lower-dimension-elements already meshed" << std::endl;
+ std::cout << " SHAPE_FILE: STEP file containing the shape to mesh" << std::endl;
+ std::cout << " HYPO_FILE: Ascii file containint the list of parameters" << std::endl;
+ std::cout << " (optional) ELEM_ORIENT_FILE: binary file containing the list of element from INPUT_MESH_FILE associated to the shape and their orientation" << std::endl;
+ std::cout << " (optional) NEW_ELEMENT_FILE: (out) contains elements and nodes added by the meshing" << std::endl;
+ std::cout << " (optional) OUTPUT_MESH_FILE: (out) MED File containing the mesh after the run of the mesher" << std::endl;
+ return 1;
+ }
+ std::string mesher=argv[1];
+ std::string input_mesh_file=argv[2];
+ std::string shape_file=argv[3];
+ std::string hypo_file=argv[4];
+ std::string element_orientation_file=argv[5];
+ std::string new_element_file=argv[6];
+ std::string output_mesh_file=argv[7];
+
+ //std::string thing;
+ //std::cin >> thing;
+
+ if (output_mesh_file == "NONE")
+ output_mesh_file = "";
+ if (element_orientation_file == "NONE")
+ element_orientation_file = "";
+ if (new_element_file == "NONE")
+ new_element_file = "";
+
+ std::cout << mesher << "\n";
+ std::cout << input_mesh_file << "\n";
+ std::cout << shape_file << "\n";
+ std::cout << hypo_file << "\n";
+ std::cout << element_orientation_file << "\n";
+ std::cout << new_element_file << "\n";
+ std::cout << output_mesh_file << "\n";
+
+ if (mesher=="GMSH3D"){
+ GMSHPlugin_GMSH_3D_SA myplugin;
+ std::cout << input_mesh_file << "\n";
+ std::cout << shape_file << "\n";
+ std::cout << hypo_file << "\n";
+ std::cout << new_element_file << "\n";
+ std::cout << output_mesh_file << "\n";
+ int run = myplugin.run(input_mesh_file,
+ shape_file,
+ hypo_file,
+ element_orientation_file,
+ new_element_file,
+ output_mesh_file );
+ }
+ else {
+ std::cerr << "Unknown mesher:" << mesher << std::endl;
+ return 1;
+ }
+ return 0;
+}
#include "GMSHPlugin_GMSH_i.hxx"
#include "GMSHPlugin_GMSH_2D_i.hxx"
#include "GMSHPlugin_GMSH_3D_i.hxx"
+#include "GMSHPlugin_GMSH_3D_Remote_i.hxx"
template <class T> class GMSHPlugin_Creator_i:public HypothesisCreator_i<T>
{
aCreator = new GMSHPlugin_Creator_i<GMSHPlugin_GMSH_2D_i>;
else if (strcmp(aHypName, "GMSH_3D") == 0)
aCreator = new GMSHPlugin_Creator_i<GMSHPlugin_GMSH_3D_i>;
+ else if (strcmp(aHypName, "GMSH_3D_Remote") == 0)
+ aCreator = new GMSHPlugin_Creator_i<GMSHPlugin_GMSH_3D_Remote_i>;
// Hypotheses
else if (strcmp(aHypName, "GMSH_Parameters") == 0)
aCreator = new GMSHPlugin_Creator_i<GMSHPlugin_Hypothesis_i>;