From: Yoann Audouin Date: Fri, 21 Oct 2022 13:03:58 +0000 (+0200) Subject: Adding parallel meshing X-Git-Url: http://git.salome-platform.org/gitweb/?a=commitdiff_plain;h=ccde3874e288c600099daa5accf7e9bfd0cfdcd7;p=plugins%2Fnetgenplugin.git Adding parallel meshing --- diff --git a/idl/NETGENPlugin_Algorithm.idl b/idl/NETGENPlugin_Algorithm.idl index 85a1ce8..b2d45fc 100644 --- a/idl/NETGENPlugin_Algorithm.idl +++ b/idl/NETGENPlugin_Algorithm.idl @@ -44,6 +44,13 @@ module NETGENPlugin { }; + /*! + * NETGENPlugin_NETGEN_3D: interface of "Remote Tetrahedron (Netgen)" algorithm + */ + interface NETGENPlugin_NETGEN_3D_Remote : NETGENPlugin::NETGENPlugin_NETGEN_3D + { + }; + /*! * NETGENPlugin_NETGEN_2D: interface of "Netgen 1D-2D" algorithm */ @@ -111,10 +118,10 @@ module NETGENPlugin void SetQuadAllowed(in boolean value); boolean GetQuadAllowed(); - + void SetUseSurfaceCurvature(in boolean value); boolean GetUseSurfaceCurvature(); - + void SetFuseEdges(in boolean value); boolean GetFuseEdges(); @@ -140,6 +147,9 @@ module NETGENPlugin void SetWorstElemMeasure(in short val ); short GetWorstElemMeasure(); + void SetNbThreads(in short val ); + short GetNbThreads(); + void SetUseDelauney(in boolean toUse); boolean GetUseDelauney(); diff --git a/src/NETGENPlugin/CMakeLists.txt b/src/NETGENPlugin/CMakeLists.txt index bfd9494..aa4746e 100644 --- a/src/NETGENPlugin/CMakeLists.txt +++ b/src/NETGENPlugin/CMakeLists.txt @@ -17,9 +17,12 @@ # See http://www.salome-platform.org/ or email : webmaster.salome@opencascade.com # +INCLUDE(UseQtExt) + # --- options --- # additional include directories INCLUDE_DIRECTORIES( + ${QT_INCLUDES} ${KERNEL_INCLUDE_DIRS} ${GUI_INCLUDE_DIRS} ${GEOM_INCLUDE_DIRS} @@ -34,7 +37,8 @@ INCLUDE_DIRECTORIES( ) # additional preprocessor / compiler flags -ADD_DEFINITIONS( +ADD_DEFINITIONS( + ${QT_DEFINITIONS} ${OMNIORB_DEFINITIONS} ${OpenCASCADE_DEFINITIONS} ${BOOST_DEFINITIONS} @@ -63,34 +67,41 @@ SET(_link_LIBRARIES ${KERNEL_SalomeNS} ${KERNEL_SALOMELocalTrace} ${KERNEL_OpUtil} + VTK::CommonCore + VTK::CommonDataModel SalomeIDLNETGENPLUGIN + Qt5::Core ) # --- headers --- # header files SET(NETGENEngine_HEADERS - NETGENPlugin_NETGEN_3D.hxx - NETGENPlugin_NETGEN_3D_i.hxx - NETGENPlugin_NETGEN_2D.hxx - NETGENPlugin_NETGEN_2D_i.hxx - NETGENPlugin_NETGEN_2D3D.hxx - NETGENPlugin_NETGEN_2D3D_i.hxx - NETGENPlugin_NETGEN_2D_ONLY.hxx - NETGENPlugin_NETGEN_2D_ONLY_i.hxx - NETGENPlugin_Hypothesis.hxx - NETGENPlugin_Hypothesis_i.hxx - NETGENPlugin_Hypothesis_2D.hxx - NETGENPlugin_Hypothesis_2D_i.hxx - NETGENPlugin_Hypothesis_3D_i.hxx - NETGENPlugin_Hypothesis_2D_ONLY_i.hxx - NETGENPlugin_SimpleHypothesis_2D.hxx - NETGENPlugin_SimpleHypothesis_3D.hxx - NETGENPlugin_SimpleHypothesis_2D_i.hxx - NETGENPlugin_SimpleHypothesis_3D_i.hxx - NETGENPlugin_Mesher.hxx + NETGENPlugin_NETGEN_3D.hxx + NETGENPlugin_NETGEN_3D_i.hxx + NETGENPlugin_NETGEN_2D.hxx + NETGENPlugin_NETGEN_2D_i.hxx + NETGENPlugin_NETGEN_2D3D.hxx + NETGENPlugin_NETGEN_2D3D_i.hxx + NETGENPlugin_NETGEN_2D_ONLY.hxx + NETGENPlugin_NETGEN_2D_ONLY_i.hxx + NETGENPlugin_Hypothesis.hxx + NETGENPlugin_Hypothesis_i.hxx + NETGENPlugin_Hypothesis_2D.hxx + NETGENPlugin_Hypothesis_2D_i.hxx + NETGENPlugin_Hypothesis_3D_i.hxx + NETGENPlugin_Hypothesis_2D_ONLY_i.hxx + NETGENPlugin_SimpleHypothesis_2D.hxx + NETGENPlugin_SimpleHypothesis_3D.hxx + NETGENPlugin_SimpleHypothesis_2D_i.hxx + NETGENPlugin_SimpleHypothesis_3D_i.hxx + NETGENPlugin_Mesher.hxx NETGENPlugin_Remesher_2D.hxx NETGENPlugin_Defs.hxx + NETGENPlugin_DriverParam.hxx + NETGENPlugin_NETGEN_3D_SA.hxx + NETGENPlugin_NETGEN_3D_Remote.hxx + NETGENPlugin_NETGEN_3D_Remote_i.hxx ) # --- sources --- @@ -118,6 +129,14 @@ SET(NETGENEngine_SOURCES NETGENPlugin_SimpleHypothesis_3D_i.cxx NETGENPlugin_Remesher_2D.cxx NETGENPlugin_i.cxx + NETGENPlugin_DriverParam.cxx + NETGENPlugin_NETGEN_3D_SA.cxx + NETGENPlugin_NETGEN_3D_Remote.cxx + NETGENPlugin_NETGEN_3D_Remote_i.cxx +) + +SET(NetgenRunner_SOURCES + NETGENPlugin_Runner_main.cxx ) # --- scripts --- @@ -134,6 +153,10 @@ ADD_LIBRARY(NETGENEngine ${NETGENEngine_SOURCES}) TARGET_LINK_LIBRARIES(NETGENEngine ${_link_LIBRARIES} ) INSTALL(TARGETS NETGENEngine EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_LIBS}) +ADD_EXECUTABLE(NETGENPlugin_Runner ${NetgenRunner_SOURCES}) +TARGET_LINK_LIBRARIES(NETGENPlugin_Runner ${_link_LIBRARIES} NETGENEngine ) +INSTALL(TARGETS NETGENPlugin_Runner EXPORT ${PROJECT_NAME}TargetGroup DESTINATION ${SALOME_INSTALL_BINS}) + INSTALL(FILES ${NETGENEngine_HEADERS} DESTINATION ${SALOME_INSTALL_HEADERS}) SALOME_INSTALL_SCRIPTS("${_bin_SCRIPTS}" ${SALOME_INSTALL_PYTHON}/salome/NETGENPlugin) diff --git a/src/NETGENPlugin/NETGENPluginBuilder.py b/src/NETGENPlugin/NETGENPluginBuilder.py index 0f156d3..162bb25 100644 --- a/src/NETGENPlugin/NETGENPluginBuilder.py +++ b/src/NETGENPlugin/NETGENPluginBuilder.py @@ -40,19 +40,20 @@ NETGEN_VERSION_MAJOR = NETGENPlugin.NETGEN_VERSION_MAJOR # Mesh algo type identifiers #---------------------------- -## Algorithm type: Netgen tetrahedron 3D algorithm, see NETGEN_3D_Algorithm +## Algorithm type: Netgen tetrahedron 3D algorithm, see NETGEN_3D_Algorithm NETGEN_3D = "NETGEN_3D" -## Algorithm type: Netgen tetrahedron 1D-2D-3D algorithm, see NETGEN_1D2D3D_Algorithm +NETGEN_3D_Remote = "NETGEN_3D_Remote" +## Algorithm type: Netgen tetrahedron 1D-2D-3D algorithm, see NETGEN_1D2D3D_Algorithm NETGEN_1D2D3D = "NETGEN_2D3D" -## Algorithm type: Netgen triangle 1D-2D algorithm, see NETGEN_1D2D_Algorithm +## Algorithm type: Netgen triangle 1D-2D algorithm, see NETGEN_1D2D_Algorithm NETGEN_1D2D = "NETGEN_2D" ## Algorithm type: Netgen triangle 2D algorithm, see NETGEN_2D_Only_Algorithm NETGEN_2D = "NETGEN_2D_ONLY" -## Algorithm type: Synonim of NETGEN_1D2D3D, see NETGEN_1D2D3D_Algorithm +## Algorithm type: Synonim of NETGEN_1D2D3D, see NETGEN_1D2D3D_Algorithm NETGEN_FULL = NETGEN_1D2D3D -## Algorithm type: Synonim of NETGEN_3D, see NETGEN_3D_Algorithm +## Algorithm type: Synonim of NETGEN_3D, see NETGEN_3D_Algorithm NETGEN = NETGEN_3D -## Algorithm type: Synonim of NETGEN_1D2D3D, see NETGEN_1D2D3D_Algorithm +## Algorithm type: Synonim of NETGEN_1D2D3D, see NETGEN_1D2D3D_Algorithm FULL_NETGEN = NETGEN_FULL #---------------------------- @@ -147,6 +148,12 @@ class NETGEN_Algorithm(Mesh_Algorithm): if self.Parameters(): self.params.SetGrowthRate(theRate) pass + ## Sets @c NbThreads parameter + # @param theRate new value of the @c NbThreads parameter + def SetNbThreads(self, theNumber): + if self.Parameters(): self.params.SetNbThreads(theNumber) + pass + ## Creates meshing hypothesis according to the chosen algorithm type # and initializes it with default parameters # @param which hypothesis type; can be either @ref SOLE (default) or @ref SIMPLE @@ -190,7 +197,7 @@ class NETGEN_Algorithm(Mesh_Algorithm): def SetLocalSizeOnShape(self, shape, size ): self.Parameters().SetLocalSizeOnShape(shape, size) pass - + pass # end of NETGEN_Algorithm class @@ -310,7 +317,7 @@ class NETGEN_1D2D3D_Algorithm(NETGEN_Algorithm): pass # end of NETGEN_1D2D3D_Algorithm class -## Triangle NETGEN 1D-2D algorithm. +## Triangle NETGEN 1D-2D algorithm. # # It can be created by calling smeshBuilder.Mesh.Triangle( smeshBuilder.NETGEN_1D2D, geom=0 ) # @@ -328,6 +335,7 @@ class NETGEN_1D2D_Algorithm(NETGEN_1D2D3D_Algorithm): # @internal docHelper = "Creates triangle 2D algorithm for faces" + ## Private constructor. # @param mesh parent mesh object algorithm is assigned to # @param geom geometry (shape/sub-shape) algorithm is assigned to; @@ -360,7 +368,9 @@ class NETGEN_2D_Only_Algorithm(NETGEN_Algorithm): ## doc string of the method # @internal docHelper = "Creates triangle 2D algorithm for faces" - + + isDefault = True + ## Private constructor. # @param mesh parent mesh object algorithm is assigned to # @param geom geometry (shape/sub-shape) algorithm is assigned to; @@ -388,7 +398,7 @@ class NETGEN_2D_Only_Algorithm(NETGEN_Algorithm): def LengthFromEdges(self): hyp = self.Hypothesis("LengthFromEdges", UseExisting=1, CompareMethod=self.CompareEqualHyp) return hyp - + ## Sets @c UseSurfaceCurvature flag # @param toUse new value of the @c UseSurfaceCurvature parameter (@c True by default) def SetUseSurfaceCurvature(self, toUse=True): @@ -470,6 +480,37 @@ class NETGEN_3D_Algorithm(NETGEN_Algorithm): pass # end of NETGEN_3D_Algorithm class +## Tetrahedron 3D algorithm +# +# It can be created by calling smeshBuilder.Mesh.Tetrahedron() or smeshBuilder.Mesh.Tetrahedron( smeshBuilder.NETGEN, geom=0 ) +# +# This algorithm generates only 3D (volumes) elements for given geometrical shape +# and, in contrast to NETGEN_1D2D3D_Algorithm class, should be used in conjunction +# with other 1D and 2D meshing algorithms. +class NETGEN_3D_Remote_Algorithm(NETGEN_3D_Algorithm): + + ## type of algorithm used with helper function in smeshBuilder.Mesh class + # @internal + algoType = NETGEN_3D_Remote + ## flag pointing either this algorithm should be used by default in dynamic method + # of smeshBuilder.Mesh class + # @internal + isDefault = False + ## doc string of the method + # @internal + docHelper = "Remotely Creates tetrahedron 3D algorithm for solids" + + ## Private constructor. + # @param mesh parent mesh object algorithm is assigned to + # @param geom geometry (shape/sub-shape) algorithm is assigned to; + # if it is @c 0 (default), the algorithm is assigned to the main shape + def __init__(self, mesh, geom=0): + NETGEN_3D_Algorithm.__init__(self, mesh, geom) + pass + + pass # end of NETGEN_3D_Remote_Algorithm class + + ## Triangle (helper) 1D-2D algorithm # diff --git a/src/NETGENPlugin/NETGENPlugin_DriverParam.cxx b/src/NETGENPlugin/NETGENPlugin_DriverParam.cxx new file mode 100644 index 0000000..c61b04c --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_DriverParam.cxx @@ -0,0 +1,172 @@ +// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, 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 : NETGENPlugin_DriverParam.hxx +// Author : Yoann AUDOUIN, EDF +// Module : NETGEN +// +#include "NETGENPlugin_DriverParam.hxx" + + +#include +#include +#include +#include + +/** + * @brief Print content of a netgen_params + * + * @param aParams The object to display + */ +void printNetgenParams(netgen_params& aParams){ + std::cout << "has_netgen_param: " << aParams.has_netgen_param << std::endl; + std::cout << "maxh: " << aParams.maxh << std::endl; + std::cout << "minh: " << aParams.minh << std::endl; + std::cout << "segmentsperedge: " << aParams.segmentsperedge << std::endl; + std::cout << "grading: " << aParams.grading << std::endl; + std::cout << "curvaturesafety: " << aParams.curvaturesafety << std::endl; + std::cout << "secondorder: " << aParams.secondorder << std::endl; + std::cout << "quad: " << aParams.quad << std::endl; + std::cout << "optimize: " << aParams.optimize << std::endl; + std::cout << "fineness: " << aParams.fineness << std::endl; + std::cout << "uselocalh: " << aParams.uselocalh << std::endl; + std::cout << "merge_solids: " << aParams.merge_solids << std::endl; + std::cout << "chordalError: " << aParams.chordalError << std::endl; + std::cout << "optsteps2d: " << aParams.optsteps2d << std::endl; + std::cout << "optsteps3d: " << aParams.optsteps3d << std::endl; + std::cout << "elsizeweight: " << aParams.elsizeweight << std::endl; + std::cout << "opterrpow: " << aParams.opterrpow << std::endl; + std::cout << "delaunay: " << aParams.delaunay << std::endl; + std::cout << "checkoverlap: " << aParams.checkoverlap << std::endl; + std::cout << "checkchartboundary: " << aParams.checkchartboundary << std::endl; + std::cout << "closeedgefac: " << aParams.closeedgefac << std::endl; + std::cout << "nbThreadMesher: " << aParams.nbThreads << std::endl; + std::cout << "has_local_size: " << aParams.has_local_size << std::endl; + std::cout << "meshsizefilename: " << aParams.meshsizefilename << std::endl; + std::cout << "has_maxelementvolume_hyp: " << aParams.has_maxelementvolume_hyp << std::endl; + std::cout << "maxElementVolume: " << aParams.maxElementVolume << std::endl; + std::cout << "has_LengthFromEdges_hyp: " << aParams.has_LengthFromEdges_hyp << std::endl; +} + +/** + * @brief Import a param_file into a netgen_params structure + * + * @param param_file Name of the file + * @param aParams Structure to fill + */ +void importNetgenParams(const std::string param_file, netgen_params& aParams){ + std::ifstream myfile(param_file); + std::string line; + + std::getline(myfile, line); + aParams.has_netgen_param = std::stoi(line); + std::getline(myfile, line); + aParams.maxh = std::stod(line); + std::getline(myfile, line); + aParams.minh = std::stod(line); + std::getline(myfile, line); + aParams.segmentsperedge = std::stod(line); + std::getline(myfile, line); + aParams.grading = std::stod(line); + std::getline(myfile, line); + aParams.curvaturesafety = std::stod(line); + std::getline(myfile, line); + aParams.secondorder = std::stoi(line); + std::getline(myfile, line); + aParams.quad = std::stoi(line); + std::getline(myfile, line); + aParams.optimize = std::stoi(line); + std::getline(myfile, line); + aParams.fineness = std::stoi(line); + std::getline(myfile, line); + aParams.uselocalh = std::stoi(line); + std::getline(myfile, line); + aParams.merge_solids = std::stoi(line); + std::getline(myfile, line); + aParams.chordalError = std::stod(line); + std::getline(myfile, line); + aParams.optsteps2d = std::stoi(line); + std::getline(myfile, line); + aParams.optsteps3d = std::stoi(line); + std::getline(myfile, line); + aParams.elsizeweight = std::stod(line); + std::getline(myfile, line); + aParams.opterrpow = std::stoi(line); + std::getline(myfile, line); + aParams.delaunay = std::stoi(line); + std::getline(myfile, line); + aParams.checkoverlap = std::stoi(line); + std::getline(myfile, line); + aParams.checkchartboundary = std::stoi(line); + std::getline(myfile, line); + aParams.closeedgefac = std::stoi(line); + std::getline(myfile, line); + aParams.nbThreads = std::stoi(line); + std::getline(myfile, line); + aParams.has_local_size = std::stoi(line); + std::getline(myfile, line); + aParams.meshsizefilename = line; + std::getline(myfile, line); + aParams.has_maxelementvolume_hyp = std::stoi(line); + std::getline(myfile, line); + aParams.maxElementVolume = std::stod(line); + std::getline(myfile, line); + aParams.maxElementVolume = std::stoi(line); + +}; + +/** + * @brief Writes the content of a netgen_param into a file + * + * @param param_file the file + * @param aParams the object + */ +void exportNetgenParams(const std::string param_file, netgen_params& aParams){ + std::ofstream myfile(param_file); + myfile << aParams.has_netgen_param << std::endl; + myfile << aParams.maxh << std::endl; + myfile << aParams.minh << std::endl; + myfile << aParams.segmentsperedge << std::endl; + myfile << aParams.grading << std::endl; + myfile << aParams.curvaturesafety << std::endl; + myfile << aParams.secondorder << std::endl; + myfile << aParams.quad << std::endl; + myfile << aParams.optimize << std::endl; + myfile << aParams.fineness << std::endl; + myfile << aParams.uselocalh << std::endl; + myfile << aParams.merge_solids << std::endl; + myfile << aParams.chordalError << std::endl; + myfile << aParams.optsteps2d << std::endl; + myfile << aParams.optsteps3d << std::endl; + myfile << aParams.elsizeweight << std::endl; + myfile << aParams.opterrpow << std::endl; + myfile << aParams.delaunay << std::endl; + myfile << aParams.checkoverlap << std::endl; + myfile << aParams.checkchartboundary << std::endl; + myfile << aParams.closeedgefac << std::endl; + myfile << aParams.nbThreads << std::endl; + myfile << aParams.has_local_size << std::endl; + myfile << aParams.meshsizefilename << std::endl; + myfile << aParams.has_maxelementvolume_hyp << std::endl; + myfile << aParams.maxElementVolume << std::endl; + myfile << aParams.has_LengthFromEdges_hyp << std::endl; +}; diff --git a/src/NETGENPlugin/NETGENPlugin_DriverParam.hxx b/src/NETGENPlugin/NETGENPlugin_DriverParam.hxx new file mode 100644 index 0000000..ea134a2 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_DriverParam.hxx @@ -0,0 +1,80 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, 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 : NETGENPlugin_DriverParam.hxx +// Author : Yoann AUDOUIN, EDF +// Module : NETGEN +// + +#ifndef _NETGENPLUGIN_DRIVERPARAM_HXX_ +#define _NETGENPLUGIN_DRIVERPARAM_HXX_ + +#include + +struct netgen_params{ + // Params from NETGENPlugin_Mesher + // True if _hypParameters is not null + bool has_netgen_param=true; + double maxh; + double minh; + double segmentsperedge; + double grading; + double curvaturesafety; + int secondorder; + int quad; + bool optimize; + int fineness; + bool uselocalh; + bool merge_solids; + double chordalError; + int optsteps2d; + int optsteps3d; + double elsizeweight; + int opterrpow; + bool delaunay; + bool checkoverlap; + bool checkchartboundary; + int closeedgefac; + + // Number of threads for the mesher + int nbThreads; + + // True if we have a mesh size file or local size info + bool has_local_size = false; + std::string meshsizefilename; + + // Params from NETGEN3D + // True if _hypMaxElementVolume is not null + bool has_maxelementvolume_hyp=false; + double maxElementVolume=0.0; + + // Params from NETGEN2D + bool has_LengthFromEdges_hyp=false; + +}; + +void printNetgenParams(netgen_params& aParams); + +void importNetgenParams(const std::string param_file, netgen_params& aParams); +void exportNetgenParams(const std::string param_file, netgen_params& aParams); + +#endif diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx index 28c9c6e..2113c96 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.cxx @@ -58,6 +58,7 @@ NETGENPlugin_Hypothesis::NETGENPlugin_Hypothesis (int hypId, SMESH_Gen * gen) _nbVolOptSteps (GetDefaultNbVolOptSteps()), _elemSizeWeight (GetDefaultElemSizeWeight()), _worstElemMeasure (GetDefaultWorstElemMeasure()), + _nbThreads (GetDefaultNbThreads()), _surfaceCurvature (GetDefaultSurfaceCurvature()), _useDelauney (GetDefaultUseDelauney()), _checkOverlapping (GetDefaultCheckOverlapping()), @@ -84,7 +85,7 @@ void NETGENPlugin_Hypothesis::SetMaxSize(double theSize) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetMinSize(double theSize) @@ -98,7 +99,7 @@ void NETGENPlugin_Hypothesis::SetMinSize(double theSize) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetSecondOrder(bool theVal) @@ -112,7 +113,7 @@ void NETGENPlugin_Hypothesis::SetSecondOrder(bool theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetOptimize(bool theVal) @@ -126,7 +127,7 @@ void NETGENPlugin_Hypothesis::SetOptimize(bool theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetFineness(Fineness theFineness) @@ -172,7 +173,7 @@ void NETGENPlugin_Hypothesis::SetFineness(Fineness theFineness) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetGrowthRate(double theRate) @@ -187,7 +188,7 @@ void NETGENPlugin_Hypothesis::SetGrowthRate(double theRate) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetNbSegPerEdge(double theVal) @@ -202,7 +203,7 @@ void NETGENPlugin_Hypothesis::SetNbSegPerEdge(double theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetNbSegPerRadius(double theVal) @@ -217,7 +218,7 @@ void NETGENPlugin_Hypothesis::SetNbSegPerRadius(double theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetChordalErrorEnabled(bool theVal) @@ -231,7 +232,7 @@ void NETGENPlugin_Hypothesis::SetChordalErrorEnabled(bool theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetChordalError(double theVal) @@ -245,7 +246,7 @@ void NETGENPlugin_Hypothesis::SetChordalError(double theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetLocalSizeOnEntry(const std::string& entry, double localSize) @@ -273,7 +274,7 @@ double NETGENPlugin_Hypothesis::GetLocalSizeOnEntry(const std::string& entry) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::UnsetLocalSizeOnEntry(const std::string& entry) @@ -284,7 +285,7 @@ void NETGENPlugin_Hypothesis::UnsetLocalSizeOnEntry(const std::string& entry) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetMeshSizeFile(const std::string& fileName) @@ -298,7 +299,7 @@ void NETGENPlugin_Hypothesis::SetMeshSizeFile(const std::string& fileName) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetQuadAllowed(bool theVal) @@ -312,7 +313,7 @@ void NETGENPlugin_Hypothesis::SetQuadAllowed(bool theVal) //============================================================================= /*! - * + * */ //============================================================================= void NETGENPlugin_Hypothesis::SetSurfaceCurvature(bool theVal) @@ -340,7 +341,7 @@ void NETGENPlugin_Hypothesis::SetFuseEdges(bool theVal) //======================================================================= //function : SetNbSurfOptSteps -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetNbSurfOptSteps( int theVal ) @@ -354,7 +355,7 @@ void NETGENPlugin_Hypothesis::SetNbSurfOptSteps( int theVal ) //======================================================================= //function : SetNbVolOptSteps -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetNbVolOptSteps( int theVal ) @@ -368,7 +369,7 @@ void NETGENPlugin_Hypothesis::SetNbVolOptSteps( int theVal ) //======================================================================= //function : SetElemSizeWeight -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetElemSizeWeight( double theVal ) @@ -382,7 +383,7 @@ void NETGENPlugin_Hypothesis::SetElemSizeWeight( double theVal ) //======================================================================= //function : SetWorstElemMeasure -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetWorstElemMeasure( int theVal ) @@ -396,7 +397,7 @@ void NETGENPlugin_Hypothesis::SetWorstElemMeasure( int theVal ) //======================================================================= //function : SetUseDelauney -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetUseDelauney( bool theVal ) @@ -410,7 +411,7 @@ void NETGENPlugin_Hypothesis::SetUseDelauney( bool theVal ) //======================================================================= //function : SetCheckOverlapping -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetCheckOverlapping( bool theVal ) @@ -424,7 +425,7 @@ void NETGENPlugin_Hypothesis::SetCheckOverlapping( bool theVal ) //======================================================================= //function : SetCheckChartBoundary -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis::SetCheckChartBoundary( bool theVal ) @@ -436,6 +437,20 @@ void NETGENPlugin_Hypothesis::SetCheckChartBoundary( bool theVal ) } } +//======================================================================= +//function : SetNbThreads +//purpose : +//======================================================================= + +void NETGENPlugin_Hypothesis::SetNbThreads( int theVal ) +{ + if (theVal != _nbThreads) + { + _nbThreads = theVal; + NotifySubMeshesHypothesisModification(); + } +} + //============================================================================= /*! * @@ -485,7 +500,7 @@ ostream & NETGENPlugin_Hypothesis::SaveTo(ostream & save) //============================================================================= /*! - * + * */ //============================================================================= istream & NETGENPlugin_Hypothesis::LoadFrom(istream & load) diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx index 133b774..e12b9ed 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis.hxx @@ -35,6 +35,7 @@ #include "Utils_SALOME_Exception.hxx" #include +#include // Parameters for work of NETGEN // @@ -125,6 +126,9 @@ public: void SetCheckChartBoundary( bool toCheck ); bool GetCheckChartBoundary() const { return _checkChartBoundary; } + void SetNbThreads( int val ); + int GetNbThreads() const { return _nbThreads; } + // the default values (taken from NETGEN 4.5 sources) static Fineness GetDefaultFineness() { return Moderate; } @@ -145,6 +149,7 @@ public: static bool GetDefaultCheckOverlapping() { return true; } static bool GetDefaultCheckChartBoundary(){ return true; } static bool GetDefaultFuseEdges() { return true; } + static int GetDefaultNbThreads() { return std::thread::hardware_concurrency(); } // Persistence virtual std::ostream & SaveTo (std::ostream & save); @@ -197,6 +202,9 @@ private: //bool _blockFilling; -- not used by netgen // (SALOME additions) bool _fuseEdges; + + // Parallelism parameters + int _nbThreads; }; #endif diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx index fd4c4fd..3af6b67 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.cxx @@ -60,7 +60,7 @@ bool NETGENPlugin_Hypothesis_i::isToSetParameter(double curValue, NETGENPlugin_Hypothesis_i:: NETGENPlugin_Hypothesis_i (PortableServer::POA_ptr thePOA, ::SMESH_Gen* theGenImpl) - : SALOME::GenericObj_i( thePOA ), + : SALOME::GenericObj_i( thePOA ), SMESH_Hypothesis_i( thePOA ), mySetMethodFlags(0) { @@ -471,7 +471,7 @@ CORBA::Boolean NETGENPlugin_Hypothesis_i::GetFuseEdges() //======================================================================= //function : SetNbSurfOptSteps -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetNbSurfOptSteps(CORBA::Short nb ) @@ -495,7 +495,7 @@ CORBA::Short NETGENPlugin_Hypothesis_i::GetNbSurfOptSteps() //======================================================================= //function : SetNbVolOptSteps -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetNbVolOptSteps(CORBA::Short nb ) @@ -520,7 +520,7 @@ CORBA::Short NETGENPlugin_Hypothesis_i::GetNbVolOptSteps() //======================================================================= //function : SetElemSizeWeight -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetElemSizeWeight(CORBA::Double size ) @@ -544,7 +544,7 @@ CORBA::Double NETGENPlugin_Hypothesis_i::GetElemSizeWeight() //======================================================================= //function : SetWorstElemMeasure -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetWorstElemMeasure(CORBA::Short val ) @@ -558,7 +558,7 @@ void NETGENPlugin_Hypothesis_i::SetWorstElemMeasure(CORBA::Short val ) //======================================================================= //function : GetWorstElemMeasure -//purpose : +//purpose : //======================================================================= CORBA::Short NETGENPlugin_Hypothesis_i::GetWorstElemMeasure() @@ -566,9 +566,33 @@ CORBA::Short NETGENPlugin_Hypothesis_i::GetWorstElemMeasure() return (CORBA::Short) GetImpl()->GetWorstElemMeasure(); } +//======================================================================= +//function : SetNbThreads +//purpose : +//======================================================================= + +void NETGENPlugin_Hypothesis_i::SetNbThreads(CORBA::Short val ) +{ + if ( GetNbThreads() != val ) + { + this->GetImpl()->SetNbThreads( val ); + SMESH::TPythonDump() << _this() << ".SetNbThreads( " << SMESH::TVar(val) << " )"; + } +} + +//======================================================================= +//function : GetNbThreads +//purpose : +//======================================================================= + +CORBA::Short NETGENPlugin_Hypothesis_i::GetNbThreads() +{ + return (CORBA::Short) GetImpl()->GetNbThreads(); +} + //======================================================================= //function : SetUseDelauney -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetUseDelauney(CORBA::Boolean toUse) @@ -582,7 +606,7 @@ void NETGENPlugin_Hypothesis_i::SetUseDelauney(CORBA::Boolean toUse) //======================================================================= //function : GetUseDelauney -//purpose : +//purpose : //======================================================================= CORBA::Boolean NETGENPlugin_Hypothesis_i::GetUseDelauney() @@ -592,7 +616,7 @@ CORBA::Boolean NETGENPlugin_Hypothesis_i::GetUseDelauney() //======================================================================= //function : SetCheckOverlapping -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetCheckOverlapping(CORBA::Boolean toCheck ) @@ -606,7 +630,7 @@ void NETGENPlugin_Hypothesis_i::SetCheckOverlapping(CORBA::Boolean toCheck ) //======================================================================= //function : GetCheckOverlapping -//purpose : +//purpose : //======================================================================= CORBA::Boolean NETGENPlugin_Hypothesis_i::GetCheckOverlapping() @@ -616,7 +640,7 @@ CORBA::Boolean NETGENPlugin_Hypothesis_i::GetCheckOverlapping() //======================================================================= //function : SetCheckChartBoundary -//purpose : +//purpose : //======================================================================= void NETGENPlugin_Hypothesis_i::SetCheckChartBoundary(CORBA::Boolean toCheck ) @@ -652,13 +676,13 @@ CORBA::Boolean NETGENPlugin_Hypothesis_i::GetCheckChartBoundary() //================================================================================ /*! - * \brief Verify whether hypothesis supports given entity type + * \brief Verify whether hypothesis supports given entity type * \param type - dimension (see SMESH::Dimension enumeration) * \retval CORBA::Boolean - TRUE if dimension is supported, FALSE otherwise - * + * * Verify whether hypothesis supports given entity type (see SMESH::Dimension enumeration) */ -//================================================================================ +//================================================================================ CORBA::Boolean NETGENPlugin_Hypothesis_i::IsDimSupported( SMESH::Dimension type ) { return type == SMESH::DIM_3D; diff --git a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx index 3f95357..5d728f0 100644 --- a/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Hypothesis_i.hxx @@ -113,6 +113,9 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_i: void SetWorstElemMeasure(CORBA::Short val ); CORBA::Short GetWorstElemMeasure(); + void SetNbThreads(CORBA::Short val ); + CORBA::Short GetNbThreads(); + void SetUseDelauney(CORBA::Boolean toUse); CORBA::Boolean GetUseDelauney(); @@ -125,7 +128,7 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_Hypothesis_i: // Get implementation ::NETGENPlugin_Hypothesis* GetImpl(); - // Verify whether hypothesis supports given entity type + // Verify whether hypothesis supports given entity type CORBA::Boolean IsDimSupported( SMESH::Dimension type ); diff --git a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx index 732a244..2d9ff3b 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.cxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.cxx @@ -380,7 +380,7 @@ namespace //================================================================================ /*! - * \brief Restrict size of elements on the given edge + * \brief Restrict size of elements on the given edge */ //================================================================================ @@ -599,20 +599,22 @@ void NETGENPlugin_Mesher::SetDefaultParameters() _fineness = NETGENPlugin_Hypothesis::GetDefaultFineness(); mparams.uselocalh = NETGENPlugin_Hypothesis::GetDefaultSurfaceCurvature(); netgen::merge_solids = NETGENPlugin_Hypothesis::GetDefaultFuseEdges(); + // Unused argument but set 0 to initialise it + mparams.elementorder = 0; #ifdef NETGEN_V6 - mparams.nthreads = std::thread::hardware_concurrency(); + mparams.nthreads = NETGENPlugin_Hypothesis::GetDefaultNbThreads(); if ( getenv( "SALOME_NETGEN_DISABLE_MULTITHREADING" )) { mparams.nthreads = 1; mparams.parallel_meshing = false; } - #endif } + //============================================================================= /*! * Pass parameters to NETGEN @@ -655,6 +657,7 @@ void NETGENPlugin_Mesher::SetParameters(const NETGENPlugin_Hypothesis* hyp) #ifdef NETGEN_V6 // std::string mparams.meshsizefilename = hyp->GetMeshSizeFile(); + mparams.nthreads = hyp->GetNbThreads(); #else // const char* mparams.meshsizefilename= hyp->GetMeshSizeFile().empty() ? 0 : hyp->GetMeshSizeFile().c_str(); @@ -1575,7 +1578,7 @@ void NETGENPlugin_Mesher::FixIntFaces(const netgen::OCCGeometry& occgeom, NETGENPlugin_Internals& internalShapes) { SMESHDS_Mesh* meshDS = internalShapes.getMesh().GetMeshDS(); - + // find ng indices of internal faces set ngFaceIds; for ( int ngFaceID = 1; ngFaceID <= occgeom.fmap.Extent(); ++ngFaceID ) @@ -1735,7 +1738,7 @@ namespace double dist3D = surf->Value( uv1.X(), uv1.Y() ).Distance( surf->Value( uv2.X(), uv2.Y() )); if ( stopHandler == 0 ) // stop recursion return dist3D; - + // start recursion if necessary double dist2D = SMESH_MesherHelper::ApplyIn2D(surf, uv1, uv2, gp_XY_Subtracted, 0).Modulus(); if ( fabs( dist3D - dist2D ) < dist2D * 1e-10 ) @@ -2205,7 +2208,7 @@ void NETGENPlugin_Mesher::AddIntVerticesInSolids(const netgen::OCCGeometry& * \param wires - data of nodes on FACE boundary * \param helper - mesher helper holding the FACE * \param nodeVec - vector of nodes in which node index == netgen ID - * \retval SMESH_ComputeErrorPtr - error description + * \retval SMESH_ComputeErrorPtr - error description */ //================================================================================ @@ -2712,7 +2715,7 @@ int NETGENPlugin_Mesher::FillSMesh(const netgen::OCCGeometry& occgeo, for ( int i = 1; i <= nbVol; ++i ) { - const netgen::Element& elem = ngMesh.VolumeElement(i); + const netgen::Element& elem = ngMesh.VolumeElement(i); int aSolidInd = elem.GetIndex(); TopoDS_Solid aSolid; if ( aSolidInd > 0 && aSolidInd <= occgeo.somap.Extent() ) @@ -2905,7 +2908,7 @@ bool NETGENPlugin_Mesher::Compute() // vector of nodes in which node index == netgen ID vector< const SMDS_MeshNode* > nodeVec; - + { // ---------------- // compute 1D mesh @@ -3511,7 +3514,7 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap) const int hugeNb = std::numeric_limits::max() / 100; // ---------------- - // evaluate 1D + // evaluate 1D // ---------------- // pass 1D simple parameters to NETGEN if ( _simpleHyp ) @@ -3618,7 +3621,7 @@ bool NETGENPlugin_Mesher::Evaluate(MapShapeNbElems& aResMap) return false; // ---------------- - // evaluate 2D + // evaluate 2D // ---------------- if ( _simpleHyp ) { if ( double area = _simpleHyp->GetMaxElementArea() ) { @@ -3820,9 +3823,9 @@ NETGENPlugin_Mesher::ReadErrors(const vector& nodeVec) } else if ( strncmp( file, "Intersecting: ", 14 ) == 0 ) { -// Intersecting: +// Intersecting: // openelement 18 with open element 126 -// 41 36 38 +// 41 36 38 // 69 70 72 file.getLine(); const char* pos = file; @@ -3939,7 +3942,7 @@ void NETGENPlugin_Mesher::toPython( const netgen::Mesh* ngMesh ) #else //////// V 5 PointIndex pi; - for (pi = PointIndex::BASE; + for (pi = PointIndex::BASE; pi < ngMesh->GetNP()+PointIndex::BASE; pi++) { outfile << "mesh.AddNode( "; @@ -4437,18 +4440,7 @@ NETGENPlugin_NetgenLibWrapper::NETGENPlugin_NetgenLibWrapper(): _ngcerr = NULL; if ( !getenv( "KEEP_NETGEN_OUTPUT" )) { - // redirect all netgen output (mycout,myerr,cout) to _outputFileName - _outputFileName = getOutputFileName(); - _ngcout = netgen::mycout; - _ngcerr = netgen::myerr; - netgen::mycout = new ofstream ( _outputFileName.c_str() ); - netgen::myerr = netgen::mycout; - _coutBuffer = std::cout.rdbuf(); -#ifdef _DEBUG_ - std::cout << "NOTE: netgen output is redirected to file " << _outputFileName << std::endl; -#else - std::cout.rdbuf( netgen::mycout->rdbuf() ); -#endif + setOutputFile(getOutputFileName()); } setMesh( Ng_NewMesh() ); @@ -4507,6 +4499,9 @@ int NETGENPlugin_NetgenLibWrapper::GenerateMesh( netgen::OCCGeometry& occgeo, if ( !ngMesh ) ngMesh = new netgen::Mesh; + // To dump mparam + // netgen::mparam.Print(std::cerr); + #ifdef NETGEN_V6 ngMesh->SetGeometry( shared_ptr( &occgeo, &NOOP_Deleter )); @@ -4569,6 +4564,27 @@ std::string NETGENPlugin_NetgenLibWrapper::getOutputFileName() return aGenericName.ToCString(); } +//================================================================================ +/*! + * \brief Set output file name for netgen log + */ +//================================================================================ + +void NETGENPlugin_NetgenLibWrapper::setOutputFile(std::string outputfile) +{ + // redirect all netgen output (mycout,myerr,cout) to _outputFileName + _outputFileName = outputfile; + _ngcout = netgen::mycout; + _ngcerr = netgen::myerr; + netgen::mycout = new ofstream ( _outputFileName.c_str() ); + netgen::myerr = netgen::mycout; + _coutBuffer = std::cout.rdbuf(); +#ifdef _DEBUG_ + std::cout << "NOTE: netgen output is redirected to file " << _outputFileName << std::endl; +#else + std::cout.rdbuf( netgen::mycout->rdbuf() ); +#endif +} //================================================================================ /*! diff --git a/src/NETGENPlugin/NETGENPlugin_Mesher.hxx b/src/NETGENPlugin/NETGENPlugin_Mesher.hxx index 48ea1ec..0a3f514 100644 --- a/src/NETGENPlugin/NETGENPlugin_Mesher.hxx +++ b/src/NETGENPlugin/NETGENPlugin_Mesher.hxx @@ -92,16 +92,20 @@ struct NETGENPLUGIN_EXPORT NETGENPlugin_NetgenLibWrapper void setMesh( nglib::Ng_Mesh* mesh ); nglib::Ng_Mesh* ngMesh() { return (nglib::Ng_Mesh*)(void*)_ngMesh; } + + static int GenerateMesh(netgen::OCCGeometry& occgeo, int startWith, int endWith, netgen::Mesh* & ngMesh); int GenerateMesh(netgen::OCCGeometry& occgeo, int startWith, int endWith ) { return GenerateMesh( occgeo, startWith, endWith, _ngMesh ); } + static void CalcLocalH( netgen::Mesh * ngMesh ); static void RemoveTmpFiles(); static int& instanceCounter(); + void setOutputFile(std::string); private: std::string getOutputFileName(); @@ -119,7 +123,7 @@ struct NETGENPLUGIN_EXPORT NETGENPlugin_NetgenLibWrapper */ //============================================================================= -class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher +class NETGENPLUGIN_EXPORT NETGENPlugin_Mesher { public: // ---------- PUBLIC METHODS ---------- @@ -272,7 +276,7 @@ public: bool isShapeToPrecompute(const TopoDS_Shape& s); // 2D meshing - // edges + // edges bool hasInternalEdges() const { return !_e2face.empty(); } bool isInternalEdge( int id ) const { return _e2face.count( id ); } const std::map& getEdgesAndVerticesWithFaces() const { return _e2face; } diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx index cd27c78..9c122c3 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_2D_ONLY.cxx @@ -76,7 +76,7 @@ using namespace nglib; //============================================================================= /*! - * + * */ //============================================================================= @@ -85,7 +85,7 @@ NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, : SMESH_2D_Algo(hypId, gen) { _name = "NETGEN_2D_ONLY"; - + _shapeType = (1 << TopAbs_FACE);// 1 bit /shape type _onlyUnaryInput = false; // treat all FACEs at once @@ -103,7 +103,7 @@ NETGENPlugin_NETGEN_2D_ONLY::NETGENPlugin_NETGEN_2D_ONLY(int hypId, //============================================================================= /*! - * + * */ //============================================================================= @@ -114,7 +114,7 @@ NETGENPlugin_NETGEN_2D_ONLY::~NETGENPlugin_NETGEN_2D_ONLY() //============================================================================= /*! - * + * */ //============================================================================= diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx index 11f0adf..8435688 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx @@ -45,6 +45,8 @@ #include #include #include +#include + #include #include @@ -63,6 +65,8 @@ #include #include +#include + /* Netgen include files */ @@ -95,7 +99,7 @@ using namespace std; //============================================================================= /*! - * + * */ //============================================================================= @@ -119,7 +123,7 @@ NETGENPlugin_NETGEN_3D::NETGENPlugin_NETGEN_3D(int hypId, SMESH_Gen* gen) //============================================================================= /*! - * + * */ //============================================================================= @@ -129,7 +133,7 @@ NETGENPlugin_NETGEN_3D::~NETGENPlugin_NETGEN_3D() //============================================================================= /*! - * + * */ //============================================================================= @@ -143,8 +147,8 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh& aMesh, _maxElementVolume = DBL_MAX; // for correct work of GetProgress(): - netgen::multithread.percent = 0.; - netgen::multithread.task = "Volume meshing"; + //netgen::multithread.percent = 0.; + //netgen::multithread.task = "Volume meshing"; _progressByTic = -1.; list::const_iterator itl; @@ -186,14 +190,102 @@ bool NETGENPlugin_NETGEN_3D::CheckHypothesis (SMESH_Mesh& aMesh, return aStatus == HYP_OK; } + + //============================================================================= /*! *Here we are going to use the NETGEN mesher */ //============================================================================= -bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, - const TopoDS_Shape& aShape) + +/** + * @brief Compute the list of already meshed Surface elements and info + * on their orientation and if they are internal + * + * @param aMesh Global Mesh + * @param aShape Shape associated to the mesh + * @param proxyMesh pointer to mesh used fo find the elements + * @param internals information on internal sub shapes + * @param helper helper associated to the mesh + * @param listElements map of surface element associated with + * their orientation and internal status + * @return true if their was some error + */ +bool NETGENPlugin_NETGEN_3D::getSurfaceElements( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_ProxyMesh::Ptr proxyMesh, + NETGENPlugin_Internals &internals, + SMESH_MesherHelper &helper, + std::map, TIDCompare>& listElements +) +{ + SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); + TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType(); + bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID ); + + for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next()) + { + const TopoDS_Shape& aShapeFace = exFa.Current(); + int faceID = meshDS->ShapeToIndex( aShapeFace ); + bool isInternalFace = internals.isInternalShape( faceID ); + bool isRev = false; + if ( checkReverse && !isInternalFace && + 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(); + if ( _quadraticMesh && + dynamic_cast< const SMESH_ProxyMesh::SubMesh*>( aSubMeshDSFace )) + { + // add medium nodes of proxy triangles to helper (#16843) + while ( iteratorElem->more() ) + helper.AddTLinks( static_cast< const SMDS_MeshFace* >( iteratorElem->next() )); + + iteratorElem = aSubMeshDSFace->GetElements(); + } + while(iteratorElem->more()){ + const SMDS_MeshElement* elem = iteratorElem->next(); + // check mesh face + if ( !elem ){ + return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); + } + if ( elem->NbCornerNodes() != 3 ){ + return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); + } + listElements[elem] = tuple(isRev, isInternalFace); + } + } + + return false; +} + +/** + * @brief Part of Compute: adding already meshed elements + * into netgen structure + * + * @param aMesh Global mesh + * @param aShape Shape associated with the mesh + * @param nodeVec Mapping between nodes mesh id and netgen structure id + * @param ngLib Wrapper on netgen lib + * @param helper helper assocaited to the mesh + * @param Netgen_NbOfNodes Number of nodes in netge structure + * @return true if there was some error + */ + +bool NETGENPlugin_NETGEN_3D::computeFillNgMesh( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + vector< const SMDS_MeshNode* > &nodeVec, + NETGENPlugin_NetgenLibWrapper &ngLib, + SMESH_MesherHelper &helper, + int &Netgen_NbOfNodes) { netgen::multithread.terminate = 0; netgen::multithread.task = "Volume meshing"; @@ -201,19 +293,15 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); - SMESH_MesherHelper helper(aMesh); _quadraticMesh = helper.IsQuadraticSubMesh(aShape); helper.SetElementsOnShape( true ); - int Netgen_NbOfNodes = 0; + Netgen_NbOfNodes = 0; double Netgen_point[3]; int Netgen_triangle[3]; - NETGENPlugin_NetgenLibWrapper ngLib; Ng_Mesh * Netgen_mesh = (Ng_Mesh*)ngLib._ngMesh; - // vector of nodes in which node index == netgen ID - vector< const SMDS_MeshNode* > nodeVec; { const int invalid_ID = -1; @@ -221,6 +309,8 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, SMESH::Controls::TSequenceOfXYZ nodesCoords; // maps nodes to ng ID + // map must be sorted by ID to ensure that we will have the same number of + // 3D element if we recompute typedef map< const SMDS_MeshNode*, int, TIDCompare > TNodeToIDMap; typedef TNodeToIDMap::value_type TN2ID; TNodeToIDMap nodeToNetgenID; @@ -231,9 +321,8 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, // --------------------------------- // Feed the Netgen with surface mesh // --------------------------------- - - TopAbs_ShapeEnum mainType = aMesh.GetShapeToMesh().ShapeType(); - bool checkReverse = ( mainType == TopAbs_COMPOUND || mainType == TopAbs_COMPSOLID ); + bool isRev=false; + bool isInternalFace=false; SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh )); if ( _viscousLayersHyp ) @@ -251,82 +340,58 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, proxyMesh.reset( Adaptor ); } - for ( TopExp_Explorer exFa( aShape, TopAbs_FACE ); exFa.More(); exFa.Next()) + // map must be sorted by ID to ensure that we will have the same number of + // 3D element if we recompute + std::map, TIDCompare> listElements; + bool ret = getSurfaceElements(aMesh, aShape, proxyMesh, internals, helper, listElements); + if(ret) + return ret; + + for ( auto const& [elem, info] : listElements ) // loop on elements on a geom face { - const TopoDS_Shape& aShapeFace = exFa.Current(); - int faceID = meshDS->ShapeToIndex( aShapeFace ); - bool isInternalFace = internals.isInternalShape( faceID ); - bool isRev = false; - if ( checkReverse && !isInternalFace && - 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(); - if ( _quadraticMesh && - dynamic_cast< const SMESH_ProxyMesh::SubMesh*>( aSubMeshDSFace )) - { - // add medium nodes of proxy triangles to helper (#16843) - while ( iteratorElem->more() ) - helper.AddTLinks( static_cast< const SMDS_MeshFace* >( iteratorElem->next() )); + isRev = get<0>(info); + isInternalFace = get<1>(info); + // Add nodes of triangles and triangles them-selves to netgen mesh - iteratorElem = aSubMeshDSFace->GetElements(); - } - while ( iteratorElem->more() ) // loop on elements on a geom face + // add three nodes of triangle + bool hasDegen = false; + for ( int iN = 0; iN < 3; ++iN ) { - // check mesh face - const SMDS_MeshElement* elem = iteratorElem->next(); - if ( !elem ) - return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); - if ( elem->NbCornerNodes() != 3 ) - return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); - - // Add nodes of triangles and triangles them-selves to netgen mesh - - // add three nodes of triangle - bool hasDegen = false; - for ( int iN = 0; iN < 3; ++iN ) + const SMDS_MeshNode* node = elem->GetNode( iN ); + const int shapeID = node->getshapeId(); + if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE && + helper.IsDegenShape( shapeID )) { - const SMDS_MeshNode* node = elem->GetNode( iN ); - const int shapeID = node->getshapeId(); - if ( node->GetPosition()->GetTypeOfPosition() == SMDS_TOP_EDGE && - helper.IsDegenShape( shapeID )) - { - // ignore all nodes on degeneraged edge and use node on its vertex instead - TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value(); - node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS ); - hasDegen = true; - } - int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second; - if ( ngID == invalid_ID ) - { - ngID = ++Netgen_NbOfNodes; - Netgen_point [ 0 ] = node->X(); - Netgen_point [ 1 ] = node->Y(); - Netgen_point [ 2 ] = node->Z(); - Ng_AddPoint(Netgen_mesh, Netgen_point); - } - Netgen_triangle[ isRev ? 2-iN : iN ] = ngID; + // ignore all nodes on degeneraged edge and use node on its vertex instead + TopoDS_Shape vertex = TopoDS_Iterator( meshDS->IndexToShape( shapeID )).Value(); + node = SMESH_Algo::VertexNode( TopoDS::Vertex( vertex ), meshDS ); + hasDegen = true; } - // add triangle - if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] || - Netgen_triangle[0] == Netgen_triangle[2] || - Netgen_triangle[2] == Netgen_triangle[1] )) - continue; - - Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); - - if ( isInternalFace && !proxyMesh->IsTemporary( elem )) + int& ngID = nodeToNetgenID.insert(TN2ID( node, invalid_ID )).first->second; + if ( ngID == invalid_ID ) { - swap( Netgen_triangle[1], Netgen_triangle[2] ); - Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); + ngID = ++Netgen_NbOfNodes; + Netgen_point [ 0 ] = node->X(); + Netgen_point [ 1 ] = node->Y(); + Netgen_point [ 2 ] = node->Z(); + Ng_AddPoint(Netgen_mesh, Netgen_point); } - } // loop on elements on a face - } // loop on faces of a SOLID or SHELL + Netgen_triangle[ isRev ? 2-iN : iN ] = ngID; + } + // add triangle + if ( hasDegen && (Netgen_triangle[0] == Netgen_triangle[1] || + Netgen_triangle[0] == Netgen_triangle[2] || + Netgen_triangle[2] == Netgen_triangle[1] )) + continue; + + Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); + + if ( isInternalFace && !proxyMesh->IsTemporary( elem )) + { + swap( Netgen_triangle[1], Netgen_triangle[2] ); + Ng_AddSurfaceElement(Netgen_mesh, NG_TRIG, Netgen_triangle); + } + } // loop on elements on a face // insert old nodes into nodeVec nodeVec.resize( nodeToNetgenID.size() + 1, 0 ); @@ -344,85 +409,238 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, internals); } } + Netgen_NbOfNodes = Ng_GetNP( Netgen_mesh ); + return false; +} - // ------------------------- - // Generate the volume mesh - // ------------------------- +/** + * @brief Part of Compute: Setting the netgen parameters from the Hypothesis + * + * @param aMesh Global mesh + * @param ngLib Wrapper on netgen lib + * @param occgeo Mapping between nodes mesh id and netgen structure id + * @param helper helper assocaited to the mesh + * @param endWith end step of netgen + * @return true if there was some error + */ +bool NETGENPlugin_NETGEN_3D::computePrepareParam( + SMESH_Mesh& aMesh, + NETGENPlugin_NetgenLibWrapper &ngLib, + netgen::OCCGeometry &occgeo, + SMESH_MesherHelper &helper, + int &endWith) - return ( ngLib._isComputeOk = compute( aMesh, helper, nodeVec, ngLib )); +{ + netgen::multithread.terminate = 0; + + netgen::Mesh* ngMesh = ngLib._ngMesh; + + NETGENPlugin_Mesher aMesher( &aMesh, helper.GetSubShape(), /*isVolume=*/true ); + + + if ( _hypParameters ) + { + aMesher.SetParameters( _hypParameters ); + + if ( !_hypParameters->GetLocalSizesAndEntries().empty() || + !_hypParameters->GetMeshSizeFile().empty() ) + { + if ( ! &ngMesh->LocalHFunction() ) + { + netgen::Point3d pmin, pmax; + ngMesh->GetBox( pmin, pmax, 0 ); + ngMesh->SetLocalH( pmin, pmax, _hypParameters->GetGrowthRate() ); + } + aMesher.SetLocalSize( occgeo, *ngMesh ); + + try { + ngMesh->LoadLocalMeshSize( netgen::mparam.meshsizefilename ); + } catch (netgen::NgException & ex) { + return error( COMPERR_BAD_PARMETERS, ex.What() ); + } + } + if ( !_hypParameters->GetOptimize() ) + endWith = netgen::MESHCONST_MESHVOLUME; + } + else if ( _hypMaxElementVolume ) + { + netgen::mparam.maxh = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); + // limitVolumeSize( ngMesh, mparam.maxh ); // result is unpredictable + } + else if ( aMesh.HasShapeToMesh() ) + { + aMesher.PrepareOCCgeometry( occgeo, helper.GetSubShape(), aMesh ); + netgen::mparam.maxh = occgeo.GetBoundingBox().Diam()/2; + } + else + { + netgen::Point3d pmin, pmax; + ngMesh->GetBox (pmin, pmax); + netgen::mparam.maxh = Dist(pmin, pmax)/2; + } + + if ( !_hypParameters && aMesh.HasShapeToMesh() ) + { + netgen::mparam.minh = aMesher.GetDefaultMinSize( helper.GetSubShape(), netgen::mparam.maxh ); + } + return false; } -// namespace -// { -// void limitVolumeSize( netgen::Mesh* ngMesh, -// double maxh ) -// { -// // get average h of faces -// double faceh = 0; -// int nbh = 0; -// for (int i = 1; i <= ngMesh->GetNSE(); i++) -// { -// const netgen::Element2d& face = ngMesh->SurfaceElement(i); -// for (int j=1; j <= face.GetNP(); ++j) -// { -// const netgen::PointIndex & i1 = face.PNumMod(j); -// const netgen::PointIndex & i2 = face.PNumMod(j+1); -// if ( i1 < i2 ) -// { -// const netgen::Point3d & p1 = ngMesh->Point( i1 ); -// const netgen::Point3d & p2 = ngMesh->Point( i2 ); -// faceh += netgen::Dist2( p1, p2 ); -// nbh++; -// } -// } -// } -// faceh = Sqrt( faceh / nbh ); - -// double compareh; -// if ( faceh < 0.5 * maxh ) compareh = -1; -// else if ( faceh > 1.5 * maxh ) compareh = 1; -// else compareh = 0; -// // cerr << "faceh " << faceh << endl; -// // cerr << "init maxh " << maxh << endl; -// // cerr << "compareh " << compareh << endl; - -// if ( compareh > 0 ) -// maxh *= 1.2; -// else -// maxh *= 0.8; -// // cerr << "maxh " << maxh << endl; - -// // get bnd box -// netgen::Point3d pmin, pmax; -// ngMesh->GetBox( pmin, pmax, 0 ); -// const double dx = pmax.X() - pmin.X(); -// const double dy = pmax.Y() - pmin.Y(); -// const double dz = pmax.Z() - pmin.Z(); - -// if ( ! & ngMesh->LocalHFunction() ) -// ngMesh->SetLocalH( pmin, pmax, compareh <= 0 ? 0.1 : 0.5 ); - -// // adjusted by SALOME_TESTS/Grids/smesh/bugs_08/I8 -// const int nbX = Max( 2, int( dx / maxh * 2 )); -// const int nbY = Max( 2, int( dy / maxh * 2 )); -// const int nbZ = Max( 2, int( dz / maxh * 2 )); - -// netgen::Point3d p; -// for ( int i = 0; i <= nbX; ++i ) -// { -// p.X() = pmin.X() + i * dx / nbX; -// for ( int j = 0; j <= nbY; ++j ) -// { -// p.Y() = pmin.Y() + j * dy / nbY; -// for ( int k = 0; k <= nbZ; ++k ) -// { -// p.Z() = pmin.Z() + k * dz / nbZ; -// ngMesh->RestrictLocalH( p, maxh ); -// } -// } -// } -// } -// } +/** + * @brief Part of Compute: call to the netgen mesher + * + * @param occgeo netgen geometry structure + * @param nodeVec Mapping between nodes mesh id and netgen structure id + * @param ngMesh netgen mesh structure + * @param ngLib Wrapper on netgen lib + * @param startWith starting step of netgen + * @param endWith end step of netgen + * @return true if there was some error + */ +bool NETGENPlugin_NETGEN_3D::computeRunMesher( + netgen::OCCGeometry &occgeo, + vector< const SMDS_MeshNode* > &nodeVec, + netgen::Mesh* ngMesh, + NETGENPlugin_NetgenLibWrapper &ngLib, + int &startWith, int &endWith) +{ + int err = 1; + + try + { + OCC_CATCH_SIGNALS; + + ngLib.CalcLocalH(ngMesh); + err = ngLib.GenerateMesh(occgeo, startWith, endWith); + + if(netgen::multithread.terminate) + return false; + if ( err ){ + error(SMESH_Comment("Error in netgen::OCCGenerateMesh() at ") << netgen::multithread.task); + } + } + catch (Standard_Failure& ex) + { + SMESH_Comment str("Exception in netgen::OCCGenerateMesh()"); + str << " at " << netgen::multithread.task + << ": " << ex.DynamicType()->Name(); + if ( ex.GetMessageString() && strlen( ex.GetMessageString() )) + str << ": " << ex.GetMessageString(); + error(str); + } + catch (netgen::NgException& exc) + { + SMESH_Comment str("NgException"); + if ( strlen( netgen::multithread.task ) > 0 ) + str << " at " << netgen::multithread.task; + str << ": " << exc.What(); + error(str); + } + catch (...) + { + SMESH_Comment str("Exception in netgen::OCCGenerateMesh()"); + if ( strlen( netgen::multithread.task ) > 0 ) + str << " at " << netgen::multithread.task; + error(str); + } + + if ( err ) + { + SMESH_ComputeErrorPtr ce = NETGENPlugin_Mesher::ReadErrors(nodeVec); + if ( ce && ce->HasBadElems() ){ + error( ce ); + } + } + + return false; +} + +/** + * @brief Part of Compute: Adding new element created by mesher to SMESH_Mesh + * + * @param nodeVec Mapping between nodes mesh id and netgen structure id + * @param ngLib Wrapper on netgen lib + * @param helper tool associated to the mesh to add element + * @param Netgen_NbOfNodes Number of nodes in netgen structure + * @return true if there was some error + */ +bool NETGENPlugin_NETGEN_3D::computeFillMesh( + vector< const SMDS_MeshNode* > &nodeVec, + NETGENPlugin_NetgenLibWrapper &ngLib, + SMESH_MesherHelper &helper, + int &Netgen_NbOfNodes + ) +{ + Ng_Mesh* Netgen_mesh = ngLib.ngMesh(); + + int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh); + int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh); + + bool isOK = ( /*status == NG_OK &&*/ Netgen_NbOfTetra > 0 );// get whatever built + if ( isOK ) + { + double Netgen_point[3]; + int Netgen_tetrahedron[4]; + + // create and insert new nodes into nodeVec + nodeVec.resize( Netgen_NbOfNodesNew + 1, 0 ); + int nodeIndex = Netgen_NbOfNodes + 1; + for ( ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex ) + { + Ng_GetPoint( Netgen_mesh, nodeIndex, Netgen_point ); + nodeVec.at(nodeIndex) = helper.AddNode(Netgen_point[0], Netgen_point[1], Netgen_point[2]); + } + + // create tetrahedrons + for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex ) + { + Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron); + try + { + helper.AddVolume (nodeVec.at( Netgen_tetrahedron[0] ), + nodeVec.at( Netgen_tetrahedron[1] ), + nodeVec.at( Netgen_tetrahedron[2] ), + nodeVec.at( Netgen_tetrahedron[3] )); + } + catch (...) + { + } + } + } + return false; +} + + +/** + * @brief Compute mesh associate to shape + * + * @param aMesh The mesh + * @param aShape The shape + * @return true fi there are some error + */ +bool NETGENPlugin_NETGEN_3D::Compute( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape) +{ + // vector of nodes in which node index == netgen ID + vector< const SMDS_MeshNode* > nodeVec; + NETGENPlugin_NetgenLibWrapper ngLib; + SMESH_MesherHelper helper(aMesh); + int startWith = netgen::MESHCONST_MESHVOLUME; + int endWith = netgen::MESHCONST_OPTVOLUME; + int Netgen_NbOfNodes; + + computeFillNgMesh(aMesh, aShape, nodeVec, ngLib, helper, Netgen_NbOfNodes); + + netgen::OCCGeometry occgeo; + computePrepareParam(aMesh, ngLib, occgeo, helper, endWith); + computeRunMesher(occgeo, nodeVec, ngLib._ngMesh, ngLib, startWith, endWith); + + computeFillMesh(nodeVec, ngLib, helper, Netgen_NbOfNodes); + + return false; + +} //================================================================================ /*! @@ -475,7 +693,7 @@ bool NETGENPlugin_NETGEN_3D::compute(SMESH_Mesh& aMesh, else if ( _hypMaxElementVolume ) { netgen::mparam.maxh = pow( 72, 1/6. ) * pow( _maxElementVolume, 1/3. ); - // limitVolumeSize( ngMesh, netgen::mparam.maxh ); // result is unpredictable + // limitVolumeSize( ngMesh, mparam.maxh ); // result is unpredictable } else if ( aMesh.HasShapeToMesh() ) { @@ -641,7 +859,7 @@ bool NETGENPlugin_NETGEN_3D::Compute(SMESH_Mesh& aMesh, return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); if ( elem->NbCornerNodes() != 3 ) return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); - + // add three nodes of triangle for ( int iN = 0; iN < 3; ++iN ) { @@ -701,14 +919,12 @@ double NETGENPlugin_NETGEN_3D::GetProgress() const strncmp( netgen::multithread.task, volMeshing, 3 ) == 0 )) { res = 0.001 + meshingRatio * netgen::multithread.percent / 100.; - //cout << netgen::multithread.task << " " <<_progressTic << "-" << netgen::multithread.percent << endl; } else // different otimizations { if ( _progressByTic < 0. ) ((NETGENPlugin_NETGEN_3D*)this)->_progressByTic = meshingRatio / _progressTic; res = _progressByTic * _progressTic; - //cout << netgen::multithread.task << " " << _progressTic << " " << res << endl; } return Min ( res, 0.98 ); } @@ -797,7 +1013,7 @@ bool NETGENPlugin_NETGEN_3D::Evaluate(SMESH_Mesh& aMesh, } SMESH_subMesh *sm = aMesh.GetSubMesh(aShape); aResMap.insert(std::make_pair(sm,aVec)); - + return true; } diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.hxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.hxx index d89f3b8..f7ebf13 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.hxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.hxx @@ -37,10 +37,15 @@ #include "SMESH_Algo.hxx" #include "Utils_SALOME_Exception.hxx" +#include +#include + class StdMeshers_ViscousLayers; class StdMeshers_MaxElementVolume; class NETGENPlugin_Hypothesis; class NETGENPlugin_NetgenLibWrapper; +class netgen_params; +class SMDS_MeshNode; class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D: public SMESH_3D_Algo { @@ -66,8 +71,44 @@ class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D: public SMESH_3D_Algo const TopoDS_Shape& aShape, MapShapeNbElems& aResMap); + bool computeFillNgMesh( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + std::vector< const SMDS_MeshNode* > &nodeVec, + NETGENPlugin_NetgenLibWrapper &ngLib, + SMESH_MesherHelper &helper, + int &Netgen_NbOfNodes); + + bool computePrepareParam( + SMESH_Mesh& aMesh, + NETGENPlugin_NetgenLibWrapper &ngLib, + netgen::OCCGeometry &occgeo, + SMESH_MesherHelper &helper, + int &endWith); + + bool computeRunMesher( + netgen::OCCGeometry &occgeo, + std::vector< const SMDS_MeshNode* > &nodeVec, + netgen::Mesh* ngMesh, + NETGENPlugin_NetgenLibWrapper &ngLib, + int &startWith, int &endWith); + + bool computeFillMesh( + std::vector< const SMDS_MeshNode* > &nodeVec, + NETGENPlugin_NetgenLibWrapper &ngLib, + SMESH_MesherHelper &helper, + int &Netgen_NbOfNodes); + protected: + virtual bool getSurfaceElements( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_ProxyMesh::Ptr proxyMesh, + NETGENPlugin_Internals &internals, + SMESH_MesherHelper &helper, + std::map, TIDCompare>& listElements); + bool compute(SMESH_Mesh& mesh, SMESH_MesherHelper& helper, std::vector< const SMDS_MeshNode* >& nodeVec, diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote.cxx new file mode 100644 index 0000000..16311c7 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote.cxx @@ -0,0 +1,384 @@ +// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, 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 : NETGENPlugin_NETGEN_3D_Remote.cxx +// Created : lundi 19 Septembre 2022 +// Author : Yoann AUDOUIN (CEA) +// Project : SALOME +//============================================================================= +// +// +#include "NETGENPlugin_NETGEN_3D_Remote.hxx" + +#include "NETGENPlugin_NETGEN_3D.hxx" + +#include "NETGENPlugin_DriverParam.hxx" +#include "NETGENPlugin_Hypothesis.hxx" + +#include "Utils_SALOME_Exception.hxx" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +namespace fs = boost::filesystem; + +/* + Netgen include files +*/ + +#ifndef OCCGEOMETRY +#define OCCGEOMETRY +#endif +#include + +#ifdef NETGEN_V5 +#include +#endif +#ifdef NETGEN_V6 +#include +#endif + +namespace nglib { +#include +} +namespace netgen { + + NETGENPLUGIN_DLL_HEADER + extern MeshingParameters mparam; + + NETGENPLUGIN_DLL_HEADER + extern volatile multithreadt multithread; +} +using namespace nglib; + +//============================================================================= +/*! + * Constructor + */ +//============================================================================= + +NETGENPlugin_NETGEN_3D_Remote::NETGENPlugin_NETGEN_3D_Remote(int hypId, SMESH_Gen * gen) + : NETGENPlugin_NETGEN_3D(hypId, gen) +{ + _name = "NETGEN_3D_Remote"; +} + +//============================================================================= +/*! + * Destructor + */ +//============================================================================= + +NETGENPlugin_NETGEN_3D_Remote::~NETGENPlugin_NETGEN_3D_Remote() +{ +} + +/** + * @brief Fill the structure netgen_param with the information from the hypothesis + * + * @param hyp the hypothesis + * @param aParams the netgen_param structure + */ +void NETGENPlugin_NETGEN_3D_Remote::fillParameters(const NETGENPlugin_Hypothesis* hyp, netgen_params &aParams) +{ + aParams.maxh = hyp->GetMaxSize(); + aParams.minh = hyp->GetMinSize(); + aParams.segmentsperedge = hyp->GetNbSegPerEdge(); + aParams.grading = hyp->GetGrowthRate(); + aParams.curvaturesafety = hyp->GetNbSegPerRadius(); + aParams.secondorder = hyp->GetSecondOrder() ? 1 : 0; + aParams.quad = hyp->GetQuadAllowed() ? 1 : 0; + aParams.optimize = hyp->GetOptimize(); + aParams.fineness = hyp->GetFineness(); + aParams.uselocalh = hyp->GetSurfaceCurvature(); + aParams.merge_solids = hyp->GetFuseEdges(); + aParams.chordalError = hyp->GetChordalErrorEnabled() ? hyp->GetChordalError() : -1.; + aParams.optsteps2d = aParams.optimize ? hyp->GetNbSurfOptSteps() : 0; + aParams.optsteps3d = aParams.optimize ? hyp->GetNbVolOptSteps() : 0; + aParams.elsizeweight = hyp->GetElemSizeWeight(); + aParams.opterrpow = hyp->GetWorstElemMeasure(); + aParams.delaunay = hyp->GetUseDelauney(); + aParams.checkoverlap = hyp->GetCheckOverlapping(); + aParams.checkchartboundary = hyp->GetCheckChartBoundary(); +#ifdef NETGEN_V6 + // std::string + aParams.meshsizefilename = hyp->GetMeshSizeFile(); + aParams.closeedgefac = 2; + aParams.nbThreads = hyp->GetNbThreads(); +#else + // const char* + aParams.meshsizefilename = hyp->GetMeshSizeFile(); + aParams.closeedgefac = 0; +#endif +} + +// + +/** + * @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 NETGENPlugin_NETGEN_3D_Remote::exportElementOrientation(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + const std::string output_file) +{ + SMESH_MesherHelper helper(aMesh); + NETGENPlugin_Internals internals( aMesh, aShape, /*is3D=*/true ); + SMESH_ProxyMesh::Ptr proxyMesh( new SMESH_ProxyMesh( aMesh )); + std::map 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 isInternalFace = internals.isInternalShape( faceID ); + bool isRev = false; + if ( !isInternalFace && + 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(); + if ( _quadraticMesh && + dynamic_cast< const SMESH_ProxyMesh::SubMesh*>( aSubMeshDSFace )) + { + // add medium nodes of proxy triangles to helper (#16843) + while ( iteratorElem->more() ) + helper.AddTLinks( static_cast< const SMDS_MeshFace* >( iteratorElem->next() )); + + 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)); + } + } +} + +/** + * @brief Compute mesh associate to shape + * + * @param aMesh The mesh + * @param aShape The shape + * @return true fi there are some error + */ +bool NETGENPlugin_NETGEN_3D_Remote::Compute(SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape) +{ + { + SMESH_MeshLocker myLocker(&aMesh); + SMESH_Hypothesis::Hypothesis_Status hypStatus; + NETGENPlugin_NETGEN_3D::CheckHypothesis(aMesh, aShape, hypStatus); + } + + + // Temporary folder for run + fs::path tmp_folder = aMesh.tmp_folder / fs::unique_path(fs::path("Volume-%%%%-%%%%")); + fs::create_directories(tmp_folder); + // Using MESH2D generated after all triangles where created. + fs::path mesh_file=aMesh.tmp_folder / 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("netgen3d_param.txt"); + fs::path log_file=tmp_folder / fs::path("run.log"); + fs::path cmd_file=tmp_folder / fs::path("cmd.log"); + std::string mesh_name = "MESH"; + + { + SMESH_MeshLocker myLocker(&aMesh); + //Writing Shape + exportShape(shape_file.string(), aShape); + + //Writing hypo + netgen_params aParams; + fillParameters(_hypParameters, aParams); + + exportNetgenParams(param_file.string(), aParams); + + // Exporting element orientation + exportElementOrientation(aMesh, aShape, element_orientation_file.string()); + } + + // Calling run_mesher + std::string cmd; + fs::path run_mesher_exe = + fs::path(std::getenv("NETGENPLUGIN_ROOT_DIR"))/ + fs::path("bin")/ + fs::path("salome")/ +#ifdef WIN32 + fs::path("NETGENPlugin_Runner.exe"); +#else + fs::path("NETGENPlugin_Runner"); +#endif + + cmd = run_mesher_exe.string() + + " NETGEN3D " + mesh_file.string() + " " + + shape_file.string() + " " + + param_file.string() + " " + + element_orientation_file.string() + " " + + new_element_file.string() + " " + + "NONE"; + // Writing command in log + { + std::ofstream flog(cmd_file.string()); + flog << cmd << endl; + flog << endl; + } + MESSAGE("Running command: "); + MESSAGE(cmd); + + + // Building arguments for QProcess + QString program = run_mesher_exe.c_str(); + QStringList arguments; + arguments << "NETGEN3D"; + arguments << mesh_file.c_str(); + arguments << shape_file.c_str(); + arguments << param_file.c_str(); + arguments << element_orientation_file.c_str(); + arguments << new_element_file.c_str(); + arguments << "NONE"; + QString out_file = log_file.c_str(); + QProcess myProcess; + 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) + myProcess.waitForFinished(-1); + int ret = myProcess.exitStatus(); + + if(ret != 0){ + // Run crahed + std::string msg = "Issue with command: \n"; + msg += "See log for more details: " + log_file.string() + "\n"; + msg += cmd + "\n"; + throw SALOME_Exception(msg); + } + + { + SMESH_MeshLocker myLocker(&aMesh); + std::ifstream df(new_element_file.string(), ios::binary); + + int Netgen_NbOfNodes; + int Netgen_NbOfNodesNew; + int Netgen_NbOfTetra; + double Netgen_point[3]; + int Netgen_tetrahedron[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*) &Netgen_NbOfNodes, sizeof(int)); + // Number of nodes added by netgen + df.read((char*) &Netgen_NbOfNodesNew, sizeof(int)); + + // Filling nodevec (correspondence netgen numbering mesh numbering) + vector< const SMDS_MeshNode* > nodeVec ( Netgen_NbOfNodesNew + 1 ); + //vector nodeTmpVec ( Netgen_NbOfNodesNew + 1 ); + SMESHDS_Mesh * meshDS = helper.GetMeshDS(); + for (int nodeIndex = 1 ; nodeIndex <= Netgen_NbOfNodes; ++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 = Netgen_NbOfNodes +1 ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex ) + { + df.read((char *) &Netgen_point, sizeof(double)*3); + + nodeVec.at(nodeIndex) = helper.AddNode(Netgen_point[0], + Netgen_point[1], + Netgen_point[2]); + } + + // Add tetrahedrons + df.read((char*) &Netgen_NbOfTetra, sizeof(int)); + + for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex ) + { + df.read((char*) &Netgen_tetrahedron, sizeof(int)*4); + helper.AddVolume( + nodeVec.at( Netgen_tetrahedron[0] ), + nodeVec.at( Netgen_tetrahedron[1] ), + nodeVec.at( Netgen_tetrahedron[2] ), + nodeVec.at( Netgen_tetrahedron[3] )); + } + } + + return true; +} + +/** + * @brief Assign submeshes to compute + * + * @param aSubMesh submesh to add + */ +void NETGENPlugin_NETGEN_3D_Remote::setSubMeshesToCompute(SMESH_subMesh * aSubMesh) +{ + SMESH_MeshLocker myLocker(aSubMesh->GetFather()); + SMESH_Algo::setSubMeshesToCompute(aSubMesh); +} diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote.hxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote.hxx new file mode 100644 index 0000000..7a23d61 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote.hxx @@ -0,0 +1,75 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, 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 : NETGENPlugin_NETGEN_3D_Remote.hxx +// Created : lundi 19 Septembre 2022 +// Author : Yoann AUDOUIN (EDF) +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_NETGEN_3D_REMOTE_HXX_ +#define _NETGENPlugin_NETGEN_3D_REMOTE_HXX_ + +#include "NETGENPlugin_NETGEN_3D.hxx" + +#include +#include + +class StdMeshers_ViscousLayers; +class StdMeshers_MaxElementVolume; +class NETGENPlugin_Hypothesis; +class NETGENPlugin_NetgenLibWrapper; +class netgen_params; +class SMDS_MeshNode; + +using namespace std; + +class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D_Remote: public NETGENPlugin_NETGEN_3D +{ + public: + NETGENPlugin_NETGEN_3D_Remote(int hypId, SMESH_Gen* gen); + virtual ~NETGENPlugin_NETGEN_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 fillParameters(const NETGENPlugin_Hypothesis* hyp, + netgen_params &aParams); + + +}; + +#endif diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote_i.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote_i.cxx new file mode 100644 index 0000000..34bbe6d --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote_i.cxx @@ -0,0 +1,80 @@ +// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, 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 : NETGENPlugin_NETGEN_3D_Remote_i.cxx +// Author : Yoann AUDOUIN (EDF) +// Module : NETGENPlugin +// $Header$ +// +#include "NETGENPlugin_NETGEN_3D_Remote_i.hxx" +#include "SMESH_Gen.hxx" + +#include "Utils_CorbaException.hxx" +#include "utilities.h" + +using namespace std; + +//============================================================================= +/*! + * NETGENPlugin_NETGEN_3D_Remote_i::NETGENPlugin_NETGEN_3D_Remote_i + * + * Constructor + */ +//============================================================================= + +NETGENPlugin_NETGEN_3D_Remote_i::NETGENPlugin_NETGEN_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 ::NETGENPlugin_NETGEN_3D_Remote( theGenImpl->GetANewId(), + theGenImpl ); +} + +//============================================================================= +/*! + * NETGENPlugin_NETGEN_3D_Remote_i::~NETGENPlugin_NETGEN_3D_Remote_i + * + * Destructor + */ +//============================================================================= + +NETGENPlugin_NETGEN_3D_Remote_i::~NETGENPlugin_NETGEN_3D_Remote_i() +{ +} + +//============================================================================= +/*! + * NETGENPlugin_NETGEN_3D_Remote_i::GetImpl + * + * Get implementation + */ +//============================================================================= + +::NETGENPlugin_NETGEN_3D_Remote* NETGENPlugin_NETGEN_3D_Remote_i::GetImpl() +{ + return ( ::NETGENPlugin_NETGEN_3D_Remote* )myBaseImpl; +} + diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote_i.hxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote_i.hxx new file mode 100644 index 0000000..405d2a5 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_Remote_i.hxx @@ -0,0 +1,58 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, 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 : NETGENPlugin_NETGEN_3D_Remote_i.hxx +// Author : Yoann AUDOUIN (EDF) +// Module : NETGENPlugin +// $Header$ +// +#ifndef _NETGENPlugin_NETGEN_3D_REMOTE_I_HXX_ +#define _NETGENPlugin_NETGEN_3D_REMOTE_I_HXX_ + +#include "NETGENPlugin_Defs.hxx" + +#include +#include CORBA_SERVER_HEADER(NETGENPlugin_Algorithm) + +#include "SMESH_3D_Algo_i.hxx" +#include "NETGENPlugin_NETGEN_3D_Remote.hxx" + +// ====================================================== +// NETGEN 3d algorithm +// ====================================================== +class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D_Remote_i: + public virtual POA_NETGENPlugin::NETGENPlugin_NETGEN_3D_Remote, + public virtual SMESH_3D_Algo_i +{ +public: + // Constructor + NETGENPlugin_NETGEN_3D_Remote_i( PortableServer::POA_ptr thePOA, + ::SMESH_Gen* theGenImpl ); + // Destructor + virtual ~NETGENPlugin_NETGEN_3D_Remote_i(); + + // Get implementation + ::NETGENPlugin_NETGEN_3D_Remote* GetImpl(); +}; + +#endif diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_SA.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_SA.cxx new file mode 100644 index 0000000..39b809b --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_SA.cxx @@ -0,0 +1,396 @@ +// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, 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 : NETGENPlugin_NETGEN_3D_SA.cxx +// Created : lundi 19 Septembre 2022 +// Author : Yoann AUDOUIN (CEA) +// Project : SALOME +//============================================================================= +// +// +#include "NETGENPlugin_NETGEN_3D_SA.hxx" + +#include "NETGENPlugin_DriverParam.hxx" +#include "NETGENPlugin_Hypothesis.hxx" +#include "StdMeshers_MaxElementVolume.hxx" + +#include +#include +#include +#include +#include +#include + + +#include +namespace fs = boost::filesystem; + +/* + Netgen include files +*/ + +#ifndef OCCGEOMETRY +#define OCCGEOMETRY +#endif +#include + +#ifdef NETGEN_V5 +#include +#endif +#ifdef NETGEN_V6 +#include +#endif + +namespace nglib { +#include +} +namespace netgen { + + NETGENPLUGIN_DLL_HEADER + extern MeshingParameters mparam; + + NETGENPLUGIN_DLL_HEADER + extern volatile multithreadt multithread; +} +using namespace nglib; + +//============================================================================= +/*! + * Constructor + */ +//============================================================================= + +NETGENPlugin_NETGEN_3D_SA::NETGENPlugin_NETGEN_3D_SA() + : NETGENPlugin_NETGEN_3D(0, new SMESH_Gen()) +{ + _name = "NETGEN_3D_SA"; +} + +//============================================================================= +/*! + * Destructor + */ +//============================================================================= + +NETGENPlugin_NETGEN_3D_SA::~NETGENPlugin_NETGEN_3D_SA() +{ + if(_gen) + delete _gen; +} + +/** + * @brief fill plugin hypothesis from the netgen_params structure + * + * @param aParams the structure + * @param gen SMESH_Gen associate with the SA + */ +void NETGENPlugin_NETGEN_3D_SA::fillHyp(netgen_params aParams) +{ + if(_gen) + std::cout << "_gen is set" << std::endl; + if(aParams.has_netgen_param){ + NETGENPlugin_Hypothesis * hypParameters = new NETGENPlugin_Hypothesis(0, GetGen()); + + hypParameters->SetMaxSize(aParams.maxh); + hypParameters->SetMinSize(aParams.minh); + hypParameters->SetNbSegPerEdge(aParams.segmentsperedge); + hypParameters->SetGrowthRate(aParams.grading); + hypParameters->SetNbSegPerRadius(aParams.curvaturesafety); + hypParameters->SetSecondOrder(aParams.secondorder); + hypParameters->SetQuadAllowed(aParams.quad); + hypParameters->SetOptimize(aParams.optimize); + hypParameters->SetFineness((NETGENPlugin_Hypothesis::Fineness)aParams.fineness); + hypParameters->SetSurfaceCurvature(aParams.uselocalh); + hypParameters->SetFuseEdges(aParams.merge_solids); + hypParameters->SetChordalErrorEnabled(aParams.chordalError); + if(aParams.optimize){ + hypParameters->SetNbSurfOptSteps(aParams.optsteps2d); + hypParameters->SetNbVolOptSteps(aParams.optsteps3d); + } + hypParameters->SetElemSizeWeight(aParams.elsizeweight); + hypParameters->SetWorstElemMeasure(aParams.opterrpow); + hypParameters->SetUseDelauney(aParams.delaunay); + hypParameters->SetCheckOverlapping(aParams.checkoverlap); + hypParameters->SetCheckChartBoundary(aParams.checkchartboundary); + hypParameters->SetMeshSizeFile(aParams.meshsizefilename); + + _hypParameters = dynamic_cast< const NETGENPlugin_Hypothesis *> (hypParameters); + } + if(aParams.has_maxelementvolume_hyp){ + _hypMaxElementVolume = new StdMeshers_MaxElementVolume(1, GetGen()); + _maxElementVolume = aParams.maxElementVolume; + } + // TODO: Handle viscous layer +} + +/** + * @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 ngLib Wrapper on netgen library + * @param new_element_file Name of the output file + * @param Netgen_NbOfNodes Number of nodes in the netgen structure + * @return true if there are some error + */ +bool NETGENPlugin_NETGEN_3D_SA::computeFillNewElementFile( + std::vector< const SMDS_MeshNode* > &nodeVec, + NETGENPlugin_NetgenLibWrapper &ngLib, + std::string new_element_file, + int &Netgen_NbOfNodes +) +{ + Ng_Mesh* Netgen_mesh = ngLib.ngMesh(); + + int Netgen_NbOfNodesNew = Ng_GetNP(Netgen_mesh); + int Netgen_NbOfTetra = Ng_GetNE(Netgen_mesh); + + bool isOK = ( Netgen_NbOfTetra > 0 ); + if ( isOK && !new_element_file.empty() ) + { + std::ofstream df(new_element_file, ios::out|ios::binary); + + double Netgen_point[3]; + int Netgen_tetrahedron[4]; + + // Writing nodevec (correspondence netgen numbering mesh numbering) + // Number of nodes + df.write((char*) &Netgen_NbOfNodes, sizeof(int)); + df.write((char*) &Netgen_NbOfNodesNew, sizeof(int)); + for (int nodeIndex = 1 ; nodeIndex <= Netgen_NbOfNodes; ++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 = Netgen_NbOfNodes +1 ; nodeIndex <= Netgen_NbOfNodesNew; ++nodeIndex ) + { + Ng_GetPoint(Netgen_mesh, nodeIndex, Netgen_point ); + // Coordinates of the point + df.write((char *) &Netgen_point, sizeof(double)*3); + } + + // create tetrahedrons + df.write((char*) &Netgen_NbOfTetra, sizeof(int)); + for ( int elemIndex = 1; elemIndex <= Netgen_NbOfTetra; ++elemIndex ) + { + Ng_GetVolumeElement(Netgen_mesh, elemIndex, Netgen_tetrahedron); + df.write((char*) &Netgen_tetrahedron, sizeof(int)*4); + } + } + return false; +} + +/** + * @brief Compute mesh associated to shape + * + * @param aShape the shape + * @param aMesh the mesh + * @param aParams netgen_params structure + * @param new_element_file Name of the file containing new element + * @param output_mesh Name of the output mesh (if empty it will not be written) + * @return true if there are some error + */ +bool NETGENPlugin_NETGEN_3D_SA::Compute( + TopoDS_Shape &aShape, + SMESH_Mesh& aMesh, + netgen_params& aParams, + std::string new_element_file, + bool output_mesh) +{ + // vector of nodes in which node index == netgen ID + vector< const SMDS_MeshNode* > nodeVec; + NETGENPlugin_NetgenLibWrapper ngLib; + SMESH_MesherHelper helper(aMesh); + int startWith = netgen::MESHCONST_MESHVOLUME; + int endWith = netgen::MESHCONST_OPTVOLUME; + int Netgen_NbOfNodes=0; + + // Changing netgen log_file putting it next to new_element_file + fs::path netgen_log_file = fs::path(new_element_file).remove_filename() / fs::path("NETGEN.out"); + + ngLib.setOutputFile(netgen_log_file.string()); + + NETGENPlugin_NETGEN_3D::computeFillNgMesh(aMesh, aShape, nodeVec, ngLib, helper, Netgen_NbOfNodes); + + netgen::OCCGeometry occgeo; + NETGENPlugin_NETGEN_3D::computePrepareParam(aMesh, ngLib, occgeo, helper, endWith); + + NETGENPlugin_NETGEN_3D::computeRunMesher(occgeo, nodeVec, ngLib._ngMesh, ngLib, startWith, endWith); + + computeFillNewElementFile(nodeVec, ngLib, new_element_file, Netgen_NbOfNodes); + + if(output_mesh) + NETGENPlugin_NETGEN_3D::computeFillMesh(nodeVec, ngLib, helper, Netgen_NbOfNodes); + + return false; +} + + +/** + * @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_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) +{ + + _element_orientation_file = element_orientation_file; + + std::unique_ptr myMesh(_gen->CreateMesh(false)); + + importMesh(input_mesh_file, *myMesh); + + // Importing shape + TopoDS_Shape myShape; + importShape(shape_file, myShape); + + // Importing hypothesis + netgen_params myParams; + + importNetgenParams(hypo_file, myParams); + fillHyp(myParams); + + MESSAGE("Meshing with netgen3d"); + int ret = Compute(myShape, *myMesh, myParams, + new_element_file, + !output_mesh_file.empty()); + + + if(ret){ + std::cerr << "Meshing failed" << std::endl; + return ret; + } + + if(!output_mesh_file.empty()){ + std::string meshName = "MESH"; + exportMesh(output_mesh_file, *myMesh, meshName); + } + + return ret; +} + +/** + * @brief Compute the list of already meshed Surface elements and info + * on their orientation and if they are internal + * + * @param aMesh Global Mesh + * @param aShape Shape associated to the mesh + * @param proxyMesh pointer to mesh used fo find the elements + * @param internals information on internal sub shapes + * @param helper helper associated to the mesh + * @param listElements map of surface element associated with + * their orientation and internal status + * @return true if their was some error + */ +bool NETGENPlugin_NETGEN_3D_SA::getSurfaceElements( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_ProxyMesh::Ptr proxyMesh, + NETGENPlugin_Internals &internals, + SMESH_MesherHelper &helper, + std::map, TIDCompare>& listElements + ) +{ + // To remove compilation warnings + (void) aShape; + (void) proxyMesh; + (void) internals; + (void) helper; + SMESHDS_Mesh* meshDS = aMesh.GetMeshDS(); + + // Get list of elements + their orientation from element_orientation file + std::map elemOrientation; + { + // Setting all element orientation to false if there no element orientation file + if(_element_orientation_file.empty()){ + MESSAGE("No element orientation file"); + + 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(); + elemOrientation[elem->GetID()] = false; + } + } else { + MESSAGE("Reading from elements from file: " << _element_orientation_file); + std::ifstream df(_element_orientation_file, ios::binary|ios::in); + int nbElement; + bool orient; + + // Warning of the use of vtkIdType (I had issue when run_mesher was compiled with internal vtk) and salome not + // Sizeof was the same but how he othered the type was different + // Maybe using another type (uint64_t) instead would be better + vtkIdType id; + df.read((char*)&nbElement, sizeof(int)); + + for(int ielem=0;ielemelementsIterator(SMDSAbs_Face); + bool isRev; + + bool isIn; + + while ( iteratorElem->more() ) // loop on elements on a geom face + { + // check mesh face + const SMDS_MeshElement* elem = iteratorElem->next(); + if ( !elem ){ + return error( COMPERR_BAD_INPUT_MESH, "Null element encounters"); + } + if ( elem->NbCornerNodes() != 3 ){ + return error( COMPERR_BAD_INPUT_MESH, "Not triangle element encounters"); + } + // Keeping only element that are in the element orientation file + isIn = elemOrientation.count(elem->GetID())==1; + if(!isIn) + continue; + // Get orientation + // Netgen requires that all the triangle point outside + isRev = elemOrientation[elem->GetID()]; + listElements[elem] = tuple(isRev, false); + } + + return false; +} diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_SA.hxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_SA.hxx new file mode 100644 index 0000000..dc7919d --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D_SA.hxx @@ -0,0 +1,81 @@ +// Copyright (C) 2007-2021 CEA/DEN, EDF R&D, 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 : NETGENPlugin_NETGEN_3D_SA.hxx +// Created : lundi 19 Septembre 2022 +// Author : Yoann AUDOUIN (EDF) +// Project : SALOME +//============================================================================= +// +#ifndef _NETGENPlugin_NETGEN_3D_SA_HXX_ +#define _NETGENPlugin_NETGEN_3D_SA_HXX_ + +#include "NETGENPlugin_NETGEN_3D.hxx" + +#include +#include + +class NETGENPlugin_NetgenLibWrapper; +class netgen_params; +class SMDS_MeshNode; + +using namespace std; + +class NETGENPLUGIN_EXPORT NETGENPlugin_NETGEN_3D_SA: public NETGENPlugin_NETGEN_3D +{ + public: + NETGENPlugin_NETGEN_3D_SA(); + virtual ~NETGENPlugin_NETGEN_3D_SA(); + + void fillHyp(netgen_params aParams); + bool Compute(TopoDS_Shape &aShape, SMESH_Mesh& aMesh, netgen_params& aParams, + std::string new_element_file, bool output_mesh); + + 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); + + protected: + + bool computeFillNewElementFile( + std::vector< const SMDS_MeshNode* > &nodeVec, + NETGENPlugin_NetgenLibWrapper &ngLib, + std::string new_element_file, + int &Netgen_NbOfNodes); + + bool getSurfaceElements( + SMESH_Mesh& aMesh, + const TopoDS_Shape& aShape, + SMESH_ProxyMesh::Ptr proxyMesh, + NETGENPlugin_Internals &internals, + SMESH_MesherHelper &helper, + std::map, TIDCompare>& listElements + ) override; + + std::string _element_orientation_file=""; +}; + +#endif diff --git a/src/NETGENPlugin/NETGENPlugin_Runner_main.cxx b/src/NETGENPlugin/NETGENPlugin_Runner_main.cxx new file mode 100644 index 0000000..95cc741 --- /dev/null +++ b/src/NETGENPlugin/NETGENPlugin_Runner_main.cxx @@ -0,0 +1,94 @@ +// Copyright (C) 2007-2022 CEA/DEN, EDF R&D, 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 : NETGENplugin_Runnner_main.cxx +// Author : Yoann AUDOUIN, EDF +// Module : NETGEN +// + +#include "NETGENPlugin_NETGEN_3D_SA.hxx" + +#include +#include +#include +#include + +/** + * @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" <> 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 = ""; + + if (mesher=="NETGEN3D"){ + NETGENPlugin_NETGEN_3D_SA myplugin; + 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 0; +} diff --git a/src/NETGENPlugin/NETGENPlugin_i.cxx b/src/NETGENPlugin/NETGENPlugin_i.cxx index 2dfc421..5394607 100644 --- a/src/NETGENPlugin/NETGENPlugin_i.cxx +++ b/src/NETGENPlugin/NETGENPlugin_i.cxx @@ -36,6 +36,7 @@ #include "NETGENPlugin_NETGEN_2D_ONLY_i.hxx" #include "NETGENPlugin_NETGEN_2D_i.hxx" #include "NETGENPlugin_NETGEN_3D_i.hxx" +#include "NETGENPlugin_NETGEN_3D_Remote_i.hxx" #include "NETGENPlugin_SimpleHypothesis_2D_i.hxx" #include "NETGENPlugin_SimpleHypothesis_3D_i.hxx" @@ -63,6 +64,8 @@ extern "C" // Algorithms if (strcmp(aHypName, "NETGEN_3D") == 0) aCreator = new NETGENPlugin_Creator_i; + else if (strcmp(aHypName, "NETGEN_3D_Remote") == 0) + aCreator = new NETGENPlugin_Creator_i; else if (strcmp(aHypName, "NETGEN_2D") == 0) aCreator = new NETGENPlugin_Creator_i; else if (strcmp(aHypName, "NETGEN_2D_ONLY") == 0)