Salome HOME
[bos #38045] [EDF] (2023-T3) Stand alone version for Netgen meshers.
[plugins/netgenplugin.git] / src / NETGENPlugin / NETGENPlugin_NETGEN_2D_SA.cxx
diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_SA.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_SA.cxx
new file mode 100644 (file)
index 0000000..d06d4e9
--- /dev/null
@@ -0,0 +1,270 @@
+// Copyright (C) 2007-2023  CEA, EDF, OPEN CASCADE
+//
+// 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
+//
+
+// NETGENPlugin : C++ implementation
+// File   : NETGENPlugin_NETGEN_2D_SA.cxx
+// Author : Cesar Conopoima (OCC)
+// Date   : 23/10/2023
+// Project   : SALOME
+//=============================================================================
+//
+#include "NETGENPlugin_NETGEN_2D_SA.hxx"
+#include "NETGENPlugin_Hypothesis_2D.hxx"
+#include "NETGENPlugin_SimpleHypothesis_2D.hxx"
+#include "NETGENPlugin_Mesher.hxx"
+
+#include <SMESHDS_Mesh.hxx>
+#include <SMESH_ControlsDef.hxx>
+#include <SMESH_Gen.hxx>
+#include <SMESH_Mesh.hxx>
+#include <SMESH_MesherHelper.hxx>
+#include <SMESH_DriverShape.hxx>
+#include <SMESH_DriverMesh.hxx>
+#include <StdMeshers_LengthFromEdges.hxx>
+#include <StdMeshers_MaxElementArea.hxx>
+#include <utilities.h>
+
+#ifdef WIN32
+#include <filesystem>
+namespace fs = std::filesystem;
+#else
+#include <boost/filesystem.hpp>
+namespace fs = boost::filesystem;
+#endif
+
+namespace nglib {
+#include <nglib.h>
+}
+#include <meshing.hpp>
+
+using namespace nglib;
+
+//=============================================================================
+/*!
+ *  
+ */
+//=============================================================================
+
+NETGENPlugin_NETGEN_2D_SA::NETGENPlugin_NETGEN_2D_SA()
+  : NETGENPlugin_NETGEN_2D_ONLY(0, new SMESH_Gen())
+{
+  _name = "NETGEN_2D_SA";  
+}
+
+//=============================================================================
+/*!
+ *  
+ */
+//=============================================================================
+
+NETGENPlugin_NETGEN_2D_SA::~NETGENPlugin_NETGEN_2D_SA()
+{
+}
+
+/**
+ * @brief fill plugin hypothesis from the netgen_params structure
+ *
+ * @param aParams the structure
+ */
+void NETGENPlugin_NETGEN_2D_SA::fillHyp(const std::string param_file, netgen_params aParams)
+{  
+
+  if( aParams.has_netgen_param && aParams.myType == hypoType::Hypo )
+  {
+    NETGENPlugin_Hypothesis_2D * hyp = new NETGENPlugin_Hypothesis_2D(0, GetGen());
+    hyp->SetMaxSize(aParams.maxh);
+    hyp->SetMinSize(aParams.minh);
+    hyp->SetGrowthRate(aParams.grading);
+    hyp->SetQuadAllowed(aParams.quad);
+    hyp->SetFineness((NETGENPlugin_Hypothesis::Fineness)aParams.fineness);
+    hyp->SetChordalErrorEnabled(aParams.chordalError);
+    if(aParams.optimize){
+      hyp->SetNbSurfOptSteps(aParams.optsteps2d);
+    }
+    _hypParameters = dynamic_cast< const NETGENPlugin_Hypothesis_2D *> (hyp);
+  }
+  else 
+  {
+    NETGENPlugin_Hypothesis * hyp = new NETGENPlugin_Hypothesis(0, GetGen());
+    if (param_file.find("lenghtfromedge") != std::string::npos )
+    {
+      _hypLengthFromEdges = dynamic_cast<const StdMeshers_LengthFromEdges*> (hyp);
+    }
+    else if ( param_file.find("maxarea") != std::string::npos )
+    {
+      StdMeshers_MaxElementArea * hyp = new StdMeshers_MaxElementArea(0, GetGen());
+
+      std::ifstream myfile(param_file);
+      std::string line;
+      double maxArea;
+      std::getline(myfile, line);
+      bool hashypothesis = std::stoi(line);
+      if ( hashypothesis )
+      {
+        std::getline(myfile, line);
+        maxArea = std::stod(line);
+        hyp->SetMaxArea( maxArea );
+        _hypMaxElementArea = static_cast<const StdMeshers_MaxElementArea*> (hyp);
+      }
+      
+      myfile.close();
+    }
+  }  
+}
+
+
+/**
+ * @brief Write a binary file containing information on the elements/nodes
+ *        created by the mesher
+ *
+ * @param premeshedNodes map of the premeshed nodes of 1D elements
+ * @param newNetgenCoordinates map of the coordinate of new netgen points created in the mesh
+ * @param newNetgenElements map of the element triangulation
+ * @return true if there are some error
+ */
+bool NETGENPlugin_NETGEN_2D_SA::fillNewElementFile( std::string new_element_file,
+                                                    const int numberOfGlobalPremeshedNodes,
+                                                    std::map<int,const SMDS_MeshNode*>& premeshedNodes, 
+                                                    std::map<int,std::vector<double>>& newNetgenCoordinates,
+                                                    std::map<int,std::vector<smIdType>>& newNetgenElements )
+{
+  MESSAGE("Writting new elements")
+
+  int NetgenNbOfNodes     = premeshedNodes.size();
+  int NetgenNbOfNodesNew  = numberOfGlobalPremeshedNodes + newNetgenCoordinates.size();
+  int NetgenNbOfTriangles = newNetgenElements.size();
+  bool isOK = ( NetgenNbOfTriangles > 0 );
+  if ( isOK && !new_element_file.empty() )
+  {
+    int    NetgenElement[3];
+    std::ofstream df(new_element_file, ios::out|ios::binary);
+    // Writing nodevec (correspondence netgen numbering mesh numbering)
+    // Number of nodes
+    df.write((char*) &numberOfGlobalPremeshedNodes, sizeof(int));
+    df.write((char*) &NetgenNbOfNodes, sizeof(int));
+    df.write((char*) &NetgenNbOfNodesNew, sizeof(int));
+    for (auto k : premeshedNodes )
+      df.write((char*) &k.first, sizeof(int));      
+        
+    // Writing info on new points
+    for (auto k : newNetgenCoordinates )
+      df.write((char*) k.second.data(), sizeof(double)*3 ); 
+      
+    // create triangles
+    df.write((char*) &NetgenNbOfTriangles, sizeof(int));
+    for ( int elemIndex = 1; elemIndex <= NetgenNbOfTriangles; ++elemIndex )
+    {
+      int nodes = newNetgenElements[ elemIndex ].size();
+      for (int i = 0; i < nodes; i++)
+        NetgenElement[ i ] = (int) newNetgenElements[ elemIndex ][ i ];
+      
+      df.write((char*) &NetgenElement, sizeof(int)* nodes );
+    }
+
+    df.close();
+  }
+  return false;
+}
+
+/**
+ * @brief Compute the mesh based on the 
+ *
+ * @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 netgen parameters
+ * @param element_orientation_file Binary file containing the orientation of surface elemnts
+ * @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 true, false
+ */
+bool NETGENPlugin_NETGEN_2D_SA::Compute( SMESH_Mesh& aMesh, TopoDS_Shape &aShape, std::string new_element_file )
+{
+  // Nodes on edge are double because each face is treat one by one, so seam edges are iterated twice 
+  vector< const SMDS_MeshNode* > nodeVec;
+  NETGENPlugin_Mesher aMesher( &aMesh, aShape, false /*isVolume=*/ );
+  NETGENPlugin_NetgenLibWrapper ngLib;
+  ngLib._isComputeOk = false;
+
+  fs::path netgen_log_file = fs::path(new_element_file).remove_filename() / fs::path("NETGEN.out");
+  MESSAGE("netgen ouput"<<netgen_log_file.string());
+  ngLib.setOutputFile(netgen_log_file.string());
+  
+  netgen::OCCGeometry occgeoComm;
+  NETGENPlugin_NETGEN_2D_ONLY::SetParameteres( aMesh, aShape, aMesher, ngLib._ngMesh, occgeoComm, false /*submesh is not supported*/ );
+
+  std::map<int,const SMDS_MeshNode*> premeshedNodes;
+  std::map<int,std::vector<double>> newNetgenCoordinates;
+  std::map<int,std::vector<smIdType>> newNetgenElements;
+  const int numberOfTotalPremeshedNodes = aMesh.NbNodes();
+  bool compute = NETGENPlugin_NETGEN_2D_ONLY::MapSegmentsToEdges( aMesh, aShape, ngLib, nodeVec,
+                                                                  premeshedNodes, newNetgenCoordinates, 
+                                                                  newNetgenElements );
+  
+  compute = fillNewElementFile(new_element_file, 
+                                numberOfTotalPremeshedNodes, 
+                                premeshedNodes, 
+                                newNetgenCoordinates, 
+                                newNetgenElements);
+  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 netgen parameters
+ * @param element_orientation_file Binary file containing the orientation of surface elemnts
+ * @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 NETGENPlugin_NETGEN_2D_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);
+  // Importing hypothesis
+  netgen_params myParams;  
+  importNetgenParams(hypo_file, myParams);
+  fillHyp(hypo_file,myParams);  
+  MESSAGE("Meshing with netgen2d");
+  int ret = (int) Compute( *myMesh, myShape, new_element_file );
+
+  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;
+}