--- /dev/null
+# contains function to compute a mesh in parallel
+from platform import java_ver
+import sys
+from tkinter import W
+import salome
+
+import time
+
+
+salome.salome_init()
+import salome_notebook
+notebook = salome_notebook.NoteBook()
+
+###
+### GEOM component
+###
+
+import GEOM
+from salome.geom import geomBuilder
+from salome.smesh import smeshBuilder
+import math
+import SALOMEDS
+
+import numpy as np
+
+geompy = geomBuilder.New()
+
+smesh = smeshBuilder.New()
+
+
+def build_seq_mesh(nbox, boxsize, offset):
+ # Create 3D faces
+ boxes = []
+ # First creating all the boxes
+ for i in range(nbox):
+ for j in range(nbox):
+ for k in range(nbox):
+
+ x_orig = i*(boxsize+offset)
+ y_orig = j*(boxsize+offset)
+ z_orig = k*(boxsize+offset)
+
+ tmp_box = geompy.MakeBoxDXDYDZ(boxsize, boxsize, boxsize)
+
+ if not i == j == k == 0:
+ box = geompy.MakeTranslation(tmp_box, x_orig,
+ y_orig, z_orig)
+ else:
+ box = tmp_box
+
+ geompy.addToStudy(box, 'box_{}:{}:{}'.format(i, j, k))
+
+ boxes.append(box)
+
+ # Create fuse of all boxes
+ all_boxes = geompy.MakeCompound(boxes)
+ geompy.addToStudy(all_boxes, 'Compound_1')
+
+ # Removing duplicates faces and edges
+ all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
+ geompy.addToStudy(all_boxes, 'Glued_Faces_1')
+
+ all_boxes = geompy.MakeGlueEdges(all_boxes, 1e-07)
+ geompy.addToStudy(all_boxes, 'rubik_cube')
+
+
+ # Building sequetial mesh
+ print("Creating mesh")
+ all_box_mesh = smesh.Mesh(all_boxes, "seq_mesh")
+
+ print("Adding algo")
+ algo3d = all_box_mesh.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D)
+
+ netgen_parameters = algo3d.Parameters()
+ netgen_parameters.SetMaxSize(34.641)
+ netgen_parameters.SetMinSize(0.141421)
+ netgen_parameters.SetOptimize(1)
+ netgen_parameters.SetCheckOverlapping(0)
+ netgen_parameters.SetCheckChartBoundary(0)
+ netgen_parameters.SetFineness(5)
+ netgen_parameters.SetNbSegPerEdge(16*(boxsize//100))
+ netgen_parameters.SetNbSegPerRadius(1.5)
+ netgen_parameters.SetGrowthRate(0.15)
+ netgen_parameters.SetChordalError(-1)
+ netgen_parameters.SetChordalErrorEnabled(0)
+ netgen_parameters.SetUseSurfaceCurvature(1)
+ netgen_parameters.SetQuadAllowed(0)
+ netgen_parameters.SetCheckOverlapping(False)
+ netgen_parameters.SetNbThreads(2)
+
+ return all_boxes, all_box_mesh, netgen_parameters
+
+def run_test(nbox=2, boxsize=100):
+ """ Run sequential mesh and parallel version of it
+
+ nbox: NUmber of boxes
+ boxsize: Size of each box
+ """
+ geom, seq_mesh, netgen_parameters = build_seq_mesh(nbox, boxsize, 0)
+
+ print("Creating Parallel Mesh")
+ par_mesh = smesh.ParallelMesh(geom, name="par_mesh")
+ par_mesh.AddGlobalHypothesis(netgen_parameters)
+ param = par_mesh.GetParallelismSettings()
+ param.SetNbThreads(6)
+
+ assert param.GetNbThreads() == 6, param.GetNbThreads()
+
+ print("Starting sequential compute")
+ start = time.monotonic()
+ is_done = seq_mesh.Compute()
+ assert is_done
+ stop = time.monotonic()
+ time_seq = stop-start
+
+ print("Starting parallel compute")
+ start = time.monotonic()
+ is_done = par_mesh.Compute()
+ assert is_done
+ stop = time.monotonic()
+ time_par = stop-start
+
+ print(" Tetrahedron: ", seq_mesh.NbTetras(), par_mesh.NbTetras())
+ print(" Triangle: ", seq_mesh.NbTriangles(), par_mesh.NbTriangles())
+ print(" edge: ", seq_mesh.NbEdges(), par_mesh.NbEdges())
+
+ assert par_mesh.NbTetras() > 0
+ assert par_mesh.NbTriangles() > 0
+ assert par_mesh.NbEdges() > 0
+
+ print("Time elapsed (seq, par): ", time_seq, time_par)
+
+def main():
+ if sys.platform == "win32":
+ print("Test disabled on Windows")
+ return
+ nbox = 2
+ boxsize = 100
+ run_test(nbox, boxsize)
+
+main()
viewing_meshes_ex01.py
radial_prism_3d_algo.py
create_dual_mesh.py
+ creating_parallel_mesh.py
)
IF(NOT WIN32)
LIST(APPEND BAD_TESTS
* Using :ref:`convert_to_from_quadratic_mesh_page` operation.
* Using an appropriate option of some meshing algorithms, which generate elements of several dimensions starting from mesh segments.
+A work in progress allow you to compute your mesh in parralle :ref:`Parallel Computing<parallel_compute>`
+
**Table of Contents**
copy_mesh.rst
create_dual_mesh.rst
connectivity.rst
+ parallel_compute.rst
--- /dev/null
+.. _parallel_compute_page:
+
+******************
+Parallel Computing
+******************
+
+
+.. warning::
+ This functionality is a work in progress.
+
+ It is only available for NETGEN.
+
+ It is only available in TUI.
+
+
+The goal here is to speed up computation by running sub-meshes in parallel
+(multi-threading).
+
+*******
+Concept
+*******
+
+.. image:: ../images/diagram_parallel_mesh.png
+
+In order to parallelise the computation of the mesh we split the geometry into:
+
+ * A 1D+2D compound
+ * A list of 3D solids
+
+Then create a sub-mesh for each of those geometry.
+And associate Hypothesis to the mesh using a hypothesis on the whole geometry
+
+We will first compute sequentially the 1D+2D compound with NETGEN_1D2D.
+
+Then we will compute all the solids in parallel. Having done the 1D+2D first
+ensure that all the solids can be computed without any concurrency.
+
+
+******
+How to
+******
+
+You follow the same principle as the creation of a sequential Mesh.
+
+
+#. First you create the mesh:
+ .. code-block:: python
+
+ par_mesh = smesh.ParallelMesh(geom, name="par_mesh")
+
+#. Define the Global Hypothesis that will be split into an hypothesis for the
+ 1D+2D compound and one for each of the 3D solids:
+ .. code-block:: python
+
+ NETGEN_3D_Parameters_1 = smesh.CreateHypothesisByAverageLength( 'NETGEN_Parameters',
+ 'NETGENEngine', 34.641, 0 )
+ par_mesh.AddGlobalHypothesis(netgen_parameters)
+
+#. Set the parameters for the parallelisation:
+ .. code-block:: python
+
+ param = par_mesh.GetParallelismSettings()
+ param.SetNbThreads(6)
+
+#. Compute the mesh:
+ .. code-block:: python
+
+ mesh.Compute()
+
+**See Also** a sample script of :ref:`tui_create_parallel_mesh`.
:download:`Download this script <../../examples/create_dual_mesh.py>`
+.. _tui_create_parallel_mesh:
+
+Creating Parallel Mesh
+======================
+
+.. literalinclude:: ../../examples/creating_parallel_mesh.py
+ :language: python
+
+:download:`Download this script <../../examples/creating_parallel_mesh.py>`
SMESH_Mesh CreateMesh( in GEOM::GEOM_Object theObject )
raises ( SALOME::SALOME_Exception );
+ /*!
+ * Create a Mesh object, given a geometry shape.
+ * Mesh is created empty (no points, no elements).
+ * Shape is explored via GEOM_Client to create local copies.
+ * of TopoDS_Shapes and bind CORBA references of shape & subshapes
+ * with TopoDS_Shapes
+ * The mesh is a parallel one
+ */
+ SMESH_Mesh CreateParallelMesh( in GEOM::GEOM_Object theObject )
+ raises ( SALOME::SALOME_Exception );
/*!
* Create an empty mesh object
*/
*/
void SetNbThreads(in long nbThreads);
/*!
+ /*!
+ * \brief Get Number of Threads
+ */
+ long GetNbThreads();
+ /*!
/*!
* Get mesh description
long GetId();
};
+ interface SMESH_SequentialMesh:SMESH_Mesh{};
+ interface SMESH_ParallelMesh:SMESH_Mesh{};
+
};
#endif
SET(SMESHimpl_HEADERS
SMESH_Gen.hxx
SMESH_Mesh.hxx
+ SMESH_SequentialMesh.hxx
+ SMESH_ParallelMesh.hxx
SMESH_subMesh.hxx
SMESH_subMeshEventListener.hxx
SMESH_Hypothesis.hxx
memoire.h
SMESH_Gen.cxx
SMESH_Mesh.cxx
+ SMESH_SequentialMesh.cxx
+ SMESH_ParallelMesh.cxx
SMESH_subMesh.cxx
SMESH_Hypothesis.cxx
SMESH_Algo.cxx
//
//#define CHRONODEF
//
-#ifndef WIN32
-#include <boost/asio.hpp>
-#endif
#include "SMESH_Gen.hxx"
#include "SMESH_DriverMesh.hxx"
#include "SMESHDS_Document.hxx"
#include "SMESH_HypoFilter.hxx"
#include "SMESH_Mesh.hxx"
+#include "SMESH_SequentialMesh.hxx"
+#include "SMESH_ParallelMesh.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_subMesh.hxx"
#include <Basics_Utils.hxx>
+#ifndef WIN32
+#include <boost/asio.hpp>
+#endif
+
using namespace std;
#ifndef WIN32
#include <boost/filesystem.hpp>
Unexpect aCatch(SalomeException);
// create a new SMESH_mesh object
- SMESH_Mesh *aMesh = new SMESH_Mesh(_localId++,
+ SMESH_Mesh *aMesh = new SMESH_SequentialMesh(
+ _localId++,
this,
theIsEmbeddedMode,
_studyContext->myDocument);
return aMesh;
}
+//=============================================================================
+/*!
+ * Creates a parallel mesh in a study.
+ * if (theIsEmbeddedMode) { mesh modification commands are not logged }
+ */
+//=============================================================================
+
+SMESH_Mesh* SMESH_Gen::CreateParallelMesh(bool theIsEmbeddedMode)
+{
+ Unexpect aCatch(SalomeException);
+
+ // create a new SMESH_mesh object
+ SMESH_Mesh *aMesh = new SMESH_ParallelMesh(
+ _localId++,
+ this,
+ theIsEmbeddedMode,
+ _studyContext->myDocument);
+ _studyContext->mapMesh[_localId-1] = aMesh;
+
+ return aMesh;
+}
//=============================================================================
/*!
continue;
// check for preview dimension limitations
- if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
+ if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
{
// clear compute state not to show previous compute errors
// if preview invoked less dimension less than previous
});
+
//=============================================================================
/*!
* Algo to run the computation of all the submeshes of a mesh in parallel
SMESH_subMeshIteratorPtr smIt;
SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape);
- // Pool of thread for computation
- // TODO: move when parallelMesh created
- aMesh.InitPoolThreads();
- aMesh.CreateTmpFolder();
-
TopAbs_ShapeEnum previousShapeType = TopAbs_VERTEX;
int nbThreads = aMesh.GetNbThreads();
MESSAGE("Compute submeshes with threads: " << nbThreads);
}
if(file_name != "")
{
- fs::path mesh_file = fs::path(aMesh.tmp_folder) / fs::path(file_name);
- SMESH_DriverMesh::exportMesh(mesh_file.string(), aMesh, "MESH");
-
+ fs::path mesh_file = fs::path(aMesh.GetTmpFolder()) / fs::path(file_name);
+ SMESH_DriverMesh::exportMesh(mesh_file.string(), aMesh, "MESH");
}
//Resetting threaded pool info
previousShapeType = shapeType;
}
// check for preview dimension limitations
- if ( aShapesId && GetShapeDim( shapeType ) > (int)aDim )
+ if ( aShapesId && SMESH_Gen::GetShapeDim( shapeType ) > (int)aDim )
{
// clear compute state not to show previous compute errors
// if preview invoked less dimension less than previous
smToCompute->ComputeStateEngine( SMESH_subMesh::CHECK_COMPUTE_STATE );
continue;
}
- boost::asio::post(*(aMesh._pool), std::bind(compute_function, smToCompute, computeEvent,
+ boost::asio::post(*(aMesh.GetPool()), std::bind(compute_function, smToCompute, computeEvent,
shapeSM, aShapeOnly, allowedSubShapes,
aShapesId));
}
aMesh.wait();
aMesh.GetMeshDS()->Modified();
- aMesh.DeleteTmpFolder();
return ret;
#endif
// ===============================================
// Mesh all the sub-shapes starting from vertices
// ===============================================
- if (aMesh.IsParallel())
- ret = parallelComputeSubMeshes(
- aMesh, aShape, aDim,
- aShapesId, allowedSubShapes,
- computeEvent,
- includeSelf,
- complexShapeFirst,
- aShapeOnly);
- else
- ret = sequentialComputeSubMeshes(
- aMesh, aShape, aDim,
- aShapesId, allowedSubShapes,
- computeEvent,
- includeSelf,
- complexShapeFirst,
- aShapeOnly);
+ ret = aMesh.ComputeSubMeshes(
+ this,
+ aMesh, aShape, aDim,
+ aShapesId, allowedSubShapes,
+ computeEvent,
+ includeSelf,
+ complexShapeFirst,
+ aShapeOnly);
return ret;
}
~SMESH_Gen();
SMESH_Mesh* CreateMesh(bool theIsEmbeddedMode);
+ SMESH_Mesh* CreateParallelMesh(bool theIsEmbeddedMode);
enum ComputeFlags
{
int GetANewId();
-private:
-
-
+public:
bool parallelComputeSubMeshes(
SMESH_Mesh & aMesh,
const TopoDS_Shape & aShape,
const bool includeSelf,
const bool complexShapeFirst,
const bool aShapeOnly);
+
+private:
+
+
+
int _localId; // unique Id of created objects, within SMESH_Gen entity
StudyContextStruct* _studyContext;
int result=pthread_create(&thread, NULL, deleteMeshDS, (void*)_meshDS);
#endif
}
- if(_pool)
- DeletePoolThreads();
}
//================================================================================
// sort submeshes according to stored mesh order
SortByMeshOrder( theSubMeshes );
}
-
-
-//=============================================================================
-/*!
- * \brief Build folder for parallel computation
- */
-//=============================================================================
-void SMESH_Mesh::CreateTmpFolder()
-{
-#ifndef WIN32
- // Temporary folder that will be used by parallel computation
- tmp_folder = fs::temp_directory_path()/fs::unique_path(fs::path("SMESH_%%%%-%%%%"));
- fs::create_directories(tmp_folder);
-#endif
-}
-//
-//=============================================================================
-/*!
- * \brief Delete temporary folder used for parallel computation
- */
-//=============================================================================
-void SMESH_Mesh::DeleteTmpFolder()
-{
-#ifndef WIN32
- fs::remove_all(tmp_folder);
-#endif
-}
#include "SMESH_ComputeError.hxx"
#include "SMESH_Controls.hxx"
#include "SMESH_Hypothesis.hxx"
+#include "SMESH_subMesh.hxx"
#include "SMDS_Iterator.hxx"
#include "Utils_SALOME_Exception.hxx"
class DriverMED_W_SMESHDS_Mesh;
+typedef std::set<int> TSetOfInt;
typedef std::list<int> TListOfInt;
typedef std::list<TListOfInt> TListOfListOfInt;
// Parallel computation functions
-#ifdef WIN32
- void Lock() {};
- void Unlock() {};
-
- int GetNbThreads(){return _NbThreads;};
- void SetNbThreads(long nbThreads){std::cout << "Warning Parallel Meshing is disabled on Windows it will behave as a slower normal compute" << std::endl;_NbThreads=nbThreads;};
-
- void InitPoolThreads(){};
- void DeletePoolThreads(){};
- void wait(){}
+ virtual void Lock(){};
+ virtual void Unlock(){};
- bool IsParallel(){return _NbThreads > 0;}
-#else
- void Lock() {_my_lock.lock();};
- void Unlock() {_my_lock.unlock();};
+ virtual int GetNbThreads(){return 0;};
+ virtual void SetNbThreads(long nbThreads){(void) nbThreads;};
- int GetNbThreads(){return _NbThreads;};
- void SetNbThreads(long nbThreads){_NbThreads=nbThreads;};
+ virtual void InitPoolThreads(){std::cout << "Should not pass here: InitPoolThread" << std::endl;};
+ virtual void DeletePoolThreads(){std::cout << "Should not pass here: DeletePoolThread" << std::endl;};
+ virtual void wait(){std::cout << "Should not pass here: wait" << std::endl;};
- void InitPoolThreads(){_pool = new boost::asio::thread_pool(_NbThreads);};
- void DeletePoolThreads(){delete _pool;};
+ virtual bool IsParallel(){std::cout << "Should not pass here: IsParallel" << std::endl;return false;};
- void wait(){_pool->join(); DeletePoolThreads(); InitPoolThreads(); }
-
- bool IsParallel(){return _NbThreads > 0;}
-#endif
-
- void CreateTmpFolder();
- void DeleteTmpFolder();
-
- // Temporary folder used during parallel Computation
-#ifndef WIN32
- boost::filesystem::path tmp_folder;
- boost::asio::thread_pool * _pool = nullptr; //thread pool for computation
-#else
- std::string tmp_folder;
- bool _pool = false;
-#endif
+ virtual boost::filesystem::path GetTmpFolder() {return "";};
+ virtual boost::asio::thread_pool* GetPool() {return NULL;};
+ virtual bool ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly){(void) gen;(void) aMesh;(void) aShape;(void) aDim;(void) aShapesId;(void) allowedSubShapes;(void) computeEvent;(void) includeSelf;(void) complexShapeFirst;(void) aShapeOnly;std::cout << "Should not pass here: computesubmesh" << std::endl;return false;};
private:
#ifndef WIN32
boost::mutex _my_lock;
#endif
- int _NbThreads=0;
+ int _NbThreads=-1;
protected:
SMESH_Mesh();
--- /dev/null
+// 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 : SMESH_ParallelMesh.cxx
+// Author : Yoann AUDOUIN, EDF
+// Module : SMESH
+//
+#include "SMESH_ParallelMesh.hxx"
+
+#include "SMESH_Gen.hxx"
+
+#ifdef WIN32
+ #include <windows.h>
+#endif
+
+#ifndef WIN32
+#include <boost/filesystem.hpp>
+namespace fs=boost::filesystem;
+#endif
+
+#ifndef WIN32
+#include <boost/asio.hpp>
+#endif
+
+#include <utilities.h>
+
+#ifdef _DEBUG_
+static int MYDEBUG = 1;
+#else
+static int MYDEBUG = 0;
+#endif
+
+SMESH_ParallelMesh::SMESH_ParallelMesh(int theLocalId,
+ SMESH_Gen* theGen,
+ bool theIsEmbeddedMode,
+ SMESHDS_Document* theDocument) :SMESH_Mesh(theLocalId,
+ theGen,
+ theIsEmbeddedMode,
+ theDocument)
+{
+ MESSAGE("SMESH_ParallelMesh::SMESH_ParallelMesh(int localId)");
+ _NbThreads = std::thread::hardware_concurrency();
+ CreateTmpFolder();
+};
+
+SMESH_ParallelMesh::~SMESH_ParallelMesh()
+{
+ DeletePoolThreads();
+ if(!MYDEBUG)
+ DeleteTmpFolder();
+};
+
+
+
+//=============================================================================
+/*!
+ * \brief Build folder for parallel computation
+ */
+//=============================================================================
+void SMESH_ParallelMesh::CreateTmpFolder()
+{
+#ifndef WIN32
+ // Temporary folder that will be used by parallel computation
+ tmp_folder = fs::temp_directory_path()/fs::unique_path(fs::path("SMESH_%%%%-%%%%"));
+ fs::create_directories(tmp_folder);
+#endif
+}
+//
+//=============================================================================
+/*!
+ * \brief Delete temporary folder used for parallel computation
+ */
+//=============================================================================
+void SMESH_ParallelMesh::DeleteTmpFolder()
+{
+#ifndef WIN32
+ fs::remove_all(tmp_folder);
+#endif
+}
+
+bool SMESH_ParallelMesh::ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly)
+{
+ InitPoolThreads();
+ return gen->parallelComputeSubMeshes(
+ aMesh, aShape, aDim,
+ aShapesId, allowedSubShapes,
+ computeEvent,
+ includeSelf,
+ complexShapeFirst,
+ aShapeOnly);
+}
--- /dev/null
+// 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 : SMESH_ParallelMesh.hxx
+// Author : Yoann AUDOUIN, EDF
+// Module : SMESH
+//
+#ifndef _SMESH_PARALLELMESH_HXX_
+#define _SMESH_PARALLELMESH_HXX_
+
+#include "SMESH_Mesh.hxx"
+
+#include "SMESH_Gen.hxx"
+#include "SMESH_subMesh.hxx"
+
+class SMESH_EXPORT SMESH_ParallelMesh: public SMESH_Mesh
+{
+ public:
+ SMESH_ParallelMesh(int theLocalId,
+ SMESH_Gen* theGen,
+ bool theIsEmbeddedMode,
+ SMESHDS_Document* theDocument);
+
+ virtual ~SMESH_ParallelMesh();
+
+ void Lock() override {_my_lock.lock();};
+ void Unlock() override {_my_lock.unlock();};
+
+ int GetNbThreads() override{return _NbThreads;};
+ void SetNbThreads(long nbThreads) override{_NbThreads=nbThreads;};
+
+ void InitPoolThreads() override {_pool = new boost::asio::thread_pool(_NbThreads);};
+ void DeletePoolThreads() override {delete _pool;};
+
+ void wait() override {_pool->join(); DeletePoolThreads(); InitPoolThreads(); };
+
+ bool IsParallel() override {return _NbThreads > 0;};
+
+ void CreateTmpFolder();
+ void DeleteTmpFolder();
+
+ boost::filesystem::path GetTmpFolder() override {return tmp_folder;};
+ boost::asio::thread_pool* GetPool() override {return _pool;};
+
+ bool ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly) override;
+
+ protected:
+ SMESH_ParallelMesh():SMESH_Mesh() {};
+ SMESH_ParallelMesh(const SMESH_ParallelMesh& aMesh):SMESH_Mesh(aMesh) {};
+ private:
+ boost::filesystem::path tmp_folder;
+ boost::asio::thread_pool * _pool = nullptr; //thread pool for computation
+};
+#endif
--- /dev/null
+// 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 : SMESH_SequentialMesh.cxx
+// Author : Yoann AUDOUIN, EDF
+// Module : SMESH
+//
+#include "SMESH_SequentialMesh.hxx"
+
+#include <TopExp_Explorer.hxx>
+#include <TopoDS.hxx>
+#include <TopoDS_Iterator.hxx>
+
+#include <utilities.h>
+
+SMESH_SequentialMesh::SMESH_SequentialMesh(int theLocalId,
+ SMESH_Gen* theGen,
+ bool theIsEmbeddedMode,
+ SMESHDS_Document* theDocument) :SMESH_Mesh(theLocalId,
+ theGen,
+ theIsEmbeddedMode,
+ theDocument)
+{
+ MESSAGE("SMESH_SequentialMesh::SMESH_SequentialMesh(int localId)");
+};
+
+SMESH_SequentialMesh::~SMESH_SequentialMesh()
+{
+};
+
+bool SMESH_SequentialMesh::ComputeSubMeshes(
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly)
+{
+ return gen->sequentialComputeSubMeshes(
+ aMesh, aShape, aDim,
+ aShapesId, allowedSubShapes,
+ computeEvent,
+ includeSelf,
+ complexShapeFirst,
+ aShapeOnly);
+};
--- /dev/null
+// 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 : SMESH_SequentialMesh.hxx
+// Author : Yoann AUDOUIN, EDF
+// Module : SMESH
+//
+#ifndef _SMESH_SEQUENTIALMESH_HXX_
+#define _SMESH_SEQUENTIALMESH_HXX_
+
+#include "SMESH_Mesh.hxx"
+
+#include "SMESH_Gen.hxx"
+#include "SMESH_subMesh.hxx"
+
+class SMESH_EXPORT SMESH_SequentialMesh: public SMESH_Mesh
+{
+ public:
+ SMESH_SequentialMesh(int theLocalId,
+ SMESH_Gen* theGen,
+ bool theIsEmbeddedMode,
+ SMESHDS_Document* theDocument);
+
+ virtual ~SMESH_SequentialMesh();
+
+ void Lock() override {};
+ void Unlock() override {};
+
+ int GetNbThreads() override {return 0;};
+ void SetNbThreads(long nbThreads) {(void) nbThreads;};
+
+ void InitPoolThreads() override {};
+ void DeletePoolThreads() override {};
+ void wait() override {};
+
+ bool IsParallel() override {return false;};
+
+ bool ComputeSubMeshes (
+ SMESH_Gen* gen,
+ SMESH_Mesh & aMesh,
+ const TopoDS_Shape & aShape,
+ const ::MeshDimension aDim,
+ TSetOfInt* aShapesId /*=0*/,
+ TopTools_IndexedMapOfShape* allowedSubShapes,
+ SMESH_subMesh::compute_event &computeEvent,
+ const bool includeSelf,
+ const bool complexShapeFirst,
+ const bool aShapeOnly) override;
+
+ protected:
+ SMESH_SequentialMesh():SMESH_Mesh() {};
+ SMESH_SequentialMesh(const SMESH_SequentialMesh& aMesh):SMESH_Mesh(aMesh) {};
+};
+#endif
TopoDS_Shape shape = _subShape;
algo->setSubMeshesToCompute(this);
// check submeshes needed
- // In parallel there would be no submesh to check
+ // When computing in parallel mode we do not have a additional layer of submesh
+ // The check should not be done in parallel as that check is not thread-safe
if (_father->HasShapeToMesh() && !_father->IsParallel()) {
bool subComputed = false, subFailed = false;
if (!algo->OnlyUnaryInput()) {
${KERNEL_Registry}
${KERNEL_SalomeHDFPersist}
${KERNEL_SalomeLifeCycleCORBA}
- ${KERNEL_TOOLSDS}
+ ${KERNEL_TOOLSDS}
${KERNEL_SalomeGenericObj}
${KERNEL_SalomeIDLKERNEL}
${KERNEL_SALOMELocalTrace}
SMESH.hxx
MG_ADAPT_i.hxx
SMESH_Homard_i.hxx
+ SMESH_SequentialMesh_i.hxx
+ SMESH_ParallelMesh_i.hxx
)
# --- sources ---
#include "SMESH_PythonDump.hxx"
#include "SMESH_ControlsDef.hxx"
#include <SMESH_BoostTxtArchive.hxx>
+#include <SMESH_SequentialMesh_i.hxx>
+#include <SMESH_ParallelMesh_i.hxx>
// to pass CORBA exception through SMESH_TRY
#define SMY_OWN_CATCH catch( SALOME::SALOME_Exception& se ) { throw se; }
*/
//=============================================================================
-SMESH::SMESH_Mesh_ptr SMESH_Gen_i::createMesh()
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::createMesh(bool parallel /*=false*/)
{
Unexpect aCatch(SALOME_SalomeException);
MESSAGE( "SMESH_Gen_i::createMesh" );
SMESH_Mesh_i* meshServant = new SMESH_Mesh_i( GetPOA(), this );
// create a new mesh object
MESSAGE("myIsEmbeddedMode " << myIsEmbeddedMode);
- meshServant->SetImpl( myGen.CreateMesh( myIsEmbeddedMode ));
+ if(parallel) {
+ meshServant->SetImpl( dynamic_cast<SMESH_Mesh*>(myGen.CreateParallelMesh( myIsEmbeddedMode )));
+ }else{
+ meshServant->SetImpl( dynamic_cast<SMESH_Mesh*>(myGen.CreateMesh( myIsEmbeddedMode )));
+ }
// activate the CORBA servant of Mesh
SMESH::SMESH_Mesh_var mesh = SMESH::SMESH_Mesh::_narrow( meshServant->_this() );
SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateMesh( GEOM::GEOM_Object_ptr theShapeObject )
{
Unexpect aCatch(SALOME_SalomeException);
- MESSAGE( "SMESH_Gen_i::CreateMesh" );
+ MESSAGE( "SMESH_Gen_i::CreateMesh(GEOM_Object_ptr)" );
// create mesh
SMESH::SMESH_Mesh_var mesh = this->createMesh();
// set shape
return mesh._retn();
}
+//=============================================================================
+/*!
+ * SMESH_Gen_i::CreateParallelMesh
+ *
+ * Create empty parallel mesh on a shape and publish it in the study
+ */
+//=============================================================================
+
+SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateParallelMesh( GEOM::GEOM_Object_ptr theShapeObject )
+{
+ Unexpect aCatch(SALOME_SalomeException);
+ MESSAGE( "SMESH_Gen_i::CreateParallelMesh" );
+ // create mesh
+ SMESH::SMESH_Mesh_var mesh = this->createMesh(true);
+ // set shape
+ SMESH_Mesh_i* meshServant = SMESH::DownCast<SMESH_Mesh_i*>( mesh );
+ ASSERT( meshServant );
+ meshServant->SetShape( theShapeObject );
+
+ // publish mesh in the study
+ if ( CanPublishInStudy( mesh ) ) {
+ SALOMEDS::StudyBuilder_var aStudyBuilder = getStudyServant()->NewBuilder();
+ aStudyBuilder->NewCommand(); // There is a transaction
+ SALOMEDS::SObject_wrap aSO = PublishMesh( mesh.in() );
+ aStudyBuilder->CommitCommand();
+ if ( !aSO->_is_nil() ) {
+ // Update Python script
+ TPythonDump(this) << aSO << " = " << this << ".CreateMesh(" << theShapeObject << ")";
+ }
+ }
+
+ return mesh._retn();
+}
+
//=============================================================================
/*!
* SMESH_Gen_i::CreateEmptyMesh
SMESH::SMESH_Mesh_ptr SMESH_Gen_i::CreateEmptyMesh()
{
Unexpect aCatch(SALOME_SalomeException);
- MESSAGE( "SMESH_Gen_i::CreateMesh" );
+ MESSAGE( "SMESH_Gen_i::CreateEmptyMesh" );
// create mesh
SMESH::SMESH_Mesh_var mesh = this->createMesh();
// Create empty mesh on a shape
SMESH::SMESH_Mesh_ptr CreateMesh( GEOM::GEOM_Object_ptr theShapeObject );
+ // Create empty parallel mesh on a shape
+ SMESH::SMESH_Mesh_ptr CreateParallelMesh( GEOM::GEOM_Object_ptr theShapeObject );
+
// Create empty mesh
SMESH::SMESH_Mesh_ptr CreateEmptyMesh();
SMESH::SMESH_Hypothesis_ptr createHypothesis( const char* theHypName,
const char* theLibName);
// Create empty mesh on shape
- SMESH::SMESH_Mesh_ptr createMesh();
+ SMESH::SMESH_Mesh_ptr createMesh(bool parallel=false);
// Check mesh icon
bool isGeomModifIcon( SMESH::SMESH_Mesh_ptr mesh );
_impl->SetNbThreads(nbThreads);
}
+//=============================================================================
+/*!
+ * \brief Get the number of threads for a parallel computation
+ */
+//=============================================================================
+CORBA::Long SMESH_Mesh_i::GetNbThreads(){
+ return _impl->GetNbThreads();
+}
+
//=============================================================================
/*!
SMESH::submesh_array_array& theSubMeshOrder,
const bool theIsDump);
+ /*!
+ * Parallelims informations
+ */
void SetNbThreads(CORBA::Long nbThreads);
+ CORBA::Long GetNbThreads();
/*!
* \brief Finds concurrent sub-meshes
obj,name = name,obj
return Mesh(self, self.geompyD, obj, name)
- def ParallelMesh(self, obj, param, nbThreads, name=0):
+ def ParallelMesh(self, obj, name=0, split_geom=True):
"""
Create a parallel mesh.
Parameters:
obj: geometrical object for meshing
name: the name for the new mesh.
- param: full mesh parameters
- nbThreads: Number of threads for parallelisation.
+ split_geom: If True split the geometry and create the assoicated
+ sub meshes
Returns:
an instance of class :class:`ParallelMesh`.
"""
- return ParallelMesh(self, self.geompyD, obj, param, nbThreads, name)
+ return ParallelMesh(self, self.geompyD, obj,
+ split_geom=split_geom, name=name)
def RemoveMesh( self, mesh ):
"""
mesh = 0
editor = 0
- def __init__(self, smeshpyD, geompyD, obj=0, name=0):
+ def __init__(self, smeshpyD, geompyD, obj=0, name=0, parallel=False):
"""
Constructor
else:
geo_name = "%s_%s to mesh"%(self.geom.GetShapeType(), id(self.geom)%100)
geompyD.addToStudy( self.geom, geo_name )
- self.SetMesh( self.smeshpyD.CreateMesh(self.geom) )
+ if parallel and isinstance(self, ParallelMesh):
+ self.SetMesh( self.smeshpyD.CreateParallelMesh(self.geom) )
+ else:
+ self.SetMesh( self.smeshpyD.CreateMesh(self.geom) )
elif isinstance(obj, SMESH._objref_SMESH_Mesh):
self.SetMesh(obj)
def _copy_netgen_param(dim, local_param, global_param):
+ """
+ Create 1D/2D/3D netgen parameters from a NETGEN 1D2D3D parameter
+ """
if dim==1:
#TODO: Try to identify why we need to substract 1
local_param.NumberOfSegments(int(global_param.GetNbSegPerEdge())-1)
local_param.SetGrowthRate(global_param.GetGrowthRate())
local_param.SetNbThreads(global_param.GetNbThreads())
+def _split_geom(geompyD, geom):
+ """
+ Splitting geometry into n solids and a 2D/1D compound
+
+ Parameters:
+ geompyD: geomBuilder instance
+ geom: geometrical object for meshing
+
+ """
+ # Splitting geometry into 3D elements and all the 2D/1D into one compound
+ object_solids = geompyD.ExtractShapes(geom, geompyD.ShapeType["SOLID"],
+ True)
+
+ solids = []
+ isolid = 0
+ for solid in object_solids:
+ isolid += 1
+ geompyD.addToStudyInFather( geom, solid, 'Solid_{}'.format(isolid) )
+ solids.append(solid)
+ # If geom is a solid ExtractShapes will return nothin in that case geom is the solids
+ if isolid == 0:
+ solids = [geom]
+
+ faces = []
+ iface = 0
+ for isolid, solid in enumerate(solids):
+ solid_faces = geompyD.ExtractShapes(solid, geompyD.ShapeType["FACE"],
+ True)
+ for face in solid_faces:
+ faces.append(face)
+ iface += 1
+ geompyD.addToStudyInFather(solid, face,
+ 'Face_{}'.format(iface))
+
+ # Creating submesh for edges 1D/2D part
+
+ all_faces = geompyD.MakeCompound(faces)
+ geompyD.addToStudy(all_faces, 'Compound_1')
+ all_faces = geompyD.MakeGlueEdges(all_faces, 1e-07)
+ all_faces = geompyD.MakeGlueFaces(all_faces, 1e-07)
+ geompyD.addToStudy(all_faces, 'global2D')
+
+ return all_faces, solids
+
+class ParallelismSettings:
+ """
+ Defines the parameters for the parallelism of ParallelMesh
+ """
+ def __init__(self, mesh):
+ """
+ Construsctor
+
+ Parameters:
+ mesh: Instance of ParallelMesh
+ """
+ if not(isinstance(mesh, ParallelMesh)):
+ raise ValueError("mesh should be a ParallelMesh")
+
+ self._mesh = mesh
+
+ def SetNbThreads(self, nbThreads):
+ """
+ Set the number of threads for multithreading
+ """
+ if nbThreads < 1:
+ raise ValueError("Number of threads must be stricly greater than 1")
+
+ self._mesh.mesh.SetNbThreads(nbThreads)
+
+ def GetNbThreads(self):
+ """
+ Get Number of threads
+ """
+ return self._mesh.mesh.GetNbThreads()
+
class ParallelMesh(Mesh):
"""
Surcharge on Mesh for parallel computation of a mesh
"""
-
- def __init__(self, smeshpyD, geompyD, geom, param, nbThreads, name=0):
+ def __init__(self, smeshpyD, geompyD, geom, split_geom=True, name=0):
"""
Create a parallel mesh.
Parameters:
+ smeshpyD: instance of smeshBuilder
+ geompyD: instance of geomBuilder
geom: geometrical object for meshing
- param: full mesh parameters
- nbThreads: Number of threads for parallelisation.
+ split_geom: If true will divide geometry on solids and 1D/2D
+ coumpound and create the associated submeshes
name: the name for the new mesh.
Returns:
if not isinstance(geom, geomBuilder.GEOM._objref_GEOM_Object):
raise ValueError("geom argument must be a geometry")
- if not isinstance(param, NETGENPlugin._objref_NETGENPlugin_Hypothesis):
- raise ValueError("param must come from NETGENPlugin")
+ # Splitting geometry into one geom containing 1D and 2D elements and a
+ # list of 3D elements
+ super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom, name, parallel=True)
- if nbThreads < 1:
- raise ValueError("Number of threads must be stricly greater than 1")
+ if split_geom:
+ self._all_faces, self._solids = _split_geom(geompyD, geom)
- # Splitting geometry into 3D elements and all the 2D/1D into one compound
- object_solids = geompyD.ExtractShapes(geom, geompyD.ShapeType["SOLID"],
- True)
+ self.UseExistingSegments()
+ self.UseExistingFaces()
- solids = []
- isolid = 0
- for solid in object_solids:
- isolid += 1
- geompyD.addToStudyInFather( geom, solid, 'Solid_{}'.format(isolid) )
- solids.append(solid)
+ self._algo2d = self.Triangle(geom=self._all_faces, algo="NETGEN_2D")
+ self._algo3d = []
- faces = []
- iface = 0
- for isolid, solid in enumerate(solids):
- solid_faces = geompyD.ExtractShapes(solid, geompyD.ShapeType["FACE"],
- True)
- for face in solid_faces:
- faces.append(face)
- iface += 1
- geompyD.addToStudyInFather(solid, face,
- 'Face_{}'.format(iface))
+ for solid_id, solid in enumerate(self._solids):
+ name = "Solid_{}".format(solid_id)
+ self.UseExistingSegments(geom=solid)
+ self.UseExistingFaces(geom=solid)
+ algo3d = self.Tetrahedron(geom=solid, algo="NETGEN_3D_Remote")
+ self._algo3d.append(algo3d)
- # Creating submesh for edges 1D/2D part
+ self._param = ParallelismSettings(self)
- all_faces = geompyD.MakeCompound(faces)
- geompyD.addToStudy(all_faces, 'Compound_1')
- all_faces = geompyD.MakeGlueEdges(all_faces, 1e-07)
- all_faces = geompyD.MakeGlueFaces(all_faces, 1e-07)
- geompyD.addToStudy(all_faces, 'global2D')
- super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom, name)
+ def GetParallelismSettings(self):
+ """
+ Return class to set parameters for the parallelism
+ """
+ return self._param
- self.mesh.SetNbThreads(nbThreads)
+ def AddGlobalHypothesis(self, hyp):
+ """
+ Split hypothesis to apply it to all the submeshes:
+ - the 1D+2D
+ - each of the 3D solids
- self.UseExistingSegments()
- self.UseExistingFaces()
+ Parameters:
+ hyp: a hypothesis to assign
- algo2d = self.Triangle(geom=all_faces, algo="NETGEN_2D")
- param2d = algo2d.Parameters()
+ """
+ if not isinstance(hyp, NETGENPlugin._objref_NETGENPlugin_Hypothesis):
+ raise ValueError("param must come from NETGENPlugin")
- _copy_netgen_param(2, param2d, param)
+ param2d = self._algo2d.Parameters()
+ _copy_netgen_param(2, param2d, hyp)
- for solid_id, solid in enumerate(solids):
- name = "Solid_{}".format(solid_id)
- self.UseExistingSegments(geom=solid)
- self.UseExistingFaces(geom=solid)
- algo3d = self.Tetrahedron(geom=solid, algo="NETGEN_3D_Remote")
+ for algo3d in self._algo3d:
param3d = algo3d.Parameters()
+ _copy_netgen_param(3, param3d, hyp)
- _copy_netgen_param(3, param3d, param)
pass # End of ParallelMesh
/*!
* \brief Auxiliary mesh
*/
- struct TmpMesh: public SMESH_Mesh
+ struct TmpMesh: public SMESH_SequentialMesh
{
TmpMesh() {
_isShapeToMesh = (_id = 0);
{
if (!SALOME::VerbosityActivated())
return;
-
+
// Not bedugged code. Last node is sometimes incorrect
const TSideFace* side = mySide;
double u = 0;
#include "SMESH_Block.hxx"
#include "SMESH_Comment.hxx"
#include "SMESH_Mesh.hxx"
+#include "SMESH_SequentialMesh.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_TypeDefs.hxx"
#include "SMESH_subMesh.hxx"
// ===============================================================
/*!
- * \brief Tool analyzing and giving access to a prism geometry
+ * \brief Tool analyzing and giving access to a prism geometry
* treating it like a block, i.e. the four side faces are
* emulated by division/uniting of missing/excess faces.
* It also manage associations between block sub-shapes and a mesh.
*/
bool GetLayersTransformation(std::vector<gp_Trsf> & trsf,
const Prism_3D::TPrismTopo& prism) const;
-
+
/*!
* \brief Return pointer to mesh
* \retval SMESH_Mesh - mesh
SMESH_ComputeErrorPtr myError;
// container of 4 side faces
- TSideFace* mySide;
+ TSideFace* mySide;
// node columns for each base edge
std::vector< TParam2ColumnMap > myParam2ColumnMaps;
// to find a column for a node by edge SMESHDS Index
#include <SMESH_Comment.hxx>
#include <SMESH_Gen.hxx>
#include <SMESH_Mesh.hxx>
+#include <SMESH_SequentialMesh.hxx>
#include <SMESH_MeshAlgos.hxx>
#include <SMESH_MeshEditor.hxx>
#include <SMESH_MesherHelper.hxx>
break;
}
case TopAbs_EDGE: {
-
+
// Get submeshes of sub-vertices
const map< int, SMESH_subMesh * >& subSM = sm->DependsOn();
if ( subSM.size() != 2 )
while ( elemIt->more() ) // loop on all mesh faces on srcFace
{
const SMDS_MeshElement* elem = elemIt->next();
- const int nbN = elem->NbCornerNodes();
+ const int nbN = elem->NbCornerNodes();
tgtNodes.resize( nbN );
helper->SetElementsOnShape( false );
for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
*/
//================================================================================
- struct QuadMesh : public SMESH_Mesh
+ struct QuadMesh : public SMESH_SequentialMesh
{
ObjectPool< TriaCoordSys > _traiLCSPool;
SMESH_ElementSearcher* _elemSearcher;
// const SMDS_MeshElement* elem = elemIt->next();
// TFaceConn& tgtNodes = newFacesVec[ iFaceSrc++ ];
- // const int nbN = elem->NbCornerNodes();
+ // const int nbN = elem->NbCornerNodes();
// tgtNodes.resize( nbN );
// for ( int i = 0; i < nbN; ++i ) // loop on nodes of the source element
// {
// {
// tgtNodeOrXY.first = srcN_tgtN->second; // tgt node exists
// }
- // else
+ // else
// {
// // find XY of src node within the quadrilateral srcFace
// if ( !block.ComputeParameters( SMESH_TNodeXYZ( srcNode ),
#include "SMESH_Gen.hxx"
#include "SMESH_MAT2d.hxx"
#include "SMESH_Mesh.hxx"
+#include "SMESH_SequentialMesh.hxx"
#include "SMESH_MeshEditor.hxx"
#include "SMESH_MesherHelper.hxx"
#include "SMESH_ProxyMesh.hxx"
return true;
}
};
-
+
//================================================================================
/*!
* \brief Constructor sets algo features
namespace
{
typedef map< const SMDS_MeshNode*, list< const SMDS_MeshNode* > > TMergeMap;
-
+
//================================================================================
/*!
* \brief Sinuous face
/*!
* \brief Temporary mesh
*/
- struct TmpMesh : public SMESH_Mesh
+ struct TmpMesh : public SMESH_SequentialMesh
{
TmpMesh()
{
theSinuEdges[1].clear();
theShortEdges[0].clear();
theShortEdges[1].clear();
-
+
vector<TopoDS_Edge> & allEdges = theSinuFace._edges;
const size_t nbEdges = allEdges.size();
if ( nbEdges < 4 && theSinuFace._nbWires == 1 )
// Find 1D algo to mesh branchEdge
-
+
// look for a most local 1D hyp assigned to the FACE
int mostSimpleShape = -1, maxShape = TopAbs_EDGE;
TopoDS_Edge edge;
nIn = nodeParams.rbegin()->second;
else
nIn = u2n->second;
-
+
// find position of distant nodes in uvsOut and uvsIn
size_t iDistOut, iDistIn;
for ( iDistOut = 0; iDistOut < uvsOut.size(); ++iDistOut )
bool StdMeshers_QuadFromMedialAxis_1D2D::Compute(SMESH_Mesh& theMesh,
const TopoDS_Shape& theShape)
{
+ std::cout << "helper_quad " << theMesh.IsParallel() << std::endl;
SMESH_MesherHelper helper( theMesh );
helper.SetSubShape( theShape );
//=======================================================================
//function : StdMeshers_RadialQuadrangle_1D2D
-//purpose :
+//purpose :
//=======================================================================
StdMeshers_RadialQuadrangle_1D2D::StdMeshers_RadialQuadrangle_1D2D(int hypId,
//=======================================================================
//function : CheckHypothesis
-//purpose :
+//purpose :
//=======================================================================
bool StdMeshers_RadialQuadrangle_1D2D::CheckHypothesis
const TopoDS_Shape& aShape,
SMESH_Hypothesis::Hypothesis_Status& aStatus)
{
- // check aShape
+ // check aShape
myNbLayerHypo = 0;
myDistributionHypo = 0;
sideEdges.splice( sideEdges.end(), edges, edges.begin() );
StdMeshers_FaceSidePtr side;
- if ( aMesh )
+ if ( aMesh )
side = StdMeshers_FaceSide::New( face, sideEdges, aMesh,
/*isFwd=*/true, /*skipMedium=*/ true, helper );
sides.push_back( side );
}
}
- int iCirc = deviation2sideInd.rbegin()->second;
+ int iCirc = deviation2sideInd.rbegin()->second;
aCircSide = sides[ iCirc ];
aLinSide1 = sides[( iCirc + 1 ) % sides.size() ];
if ( sides.size() > 2 )
centerUV = nodes.back().UV();
}
// ------------------------------------------------------------------------------------------
- else // nbSides == 3
+ else // nbSides == 3
{
// one curve must be a part of ellipse and 2 other curves must be segments of line
if ( !TNodeDistributor::GetDistributor(*mesh)->Compute( positions, linSide->Edge(0),
*curve, f, l, *mesh, hyp1D ))
{
- if ( myDistributionHypo ) { // bad hyp assigned
+ if ( myDistributionHypo ) { // bad hyp assigned
return error( TNodeDistributor::GetDistributor(*mesh)->GetComputeError() );
}
else {
}
}
}
-
+
if ( positions.empty() ) // try to use nb of layers
{
if ( !nbLayers )
//=======================================================================
//function : Evaluate
-//purpose :
+//purpose :
//=======================================================================
bool StdMeshers_RadialQuadrangle_1D2D::Evaluate(SMESH_Mesh& aMesh,
return false;
}
// ------------------------------------------------------------------------------------------
- else // nbSides == 3
+ else // nbSides == 3
{
if ( !computeLayerPositions(( linSide1->Length() > linSide2->Length() ) ? linSide1 : linSide2,
layerPositions ))
if ( SMDSEntity_Quad_Edge < (int) nbElems.size() )
nbCircSegments += ( nbElems[ SMDSEntity_Edge ] + nbElems[ SMDSEntity_Quad_Edge ]);
}
-
+
smIdType nbQuads = nbCircSegments * ( layerPositions.size() - 1 );
smIdType nbTria = nbCircSegments;
smIdType nbNodes = ( nbCircSegments - 1 ) * ( layerPositions.size() - 2 );
+++ /dev/null
-# contains function to compute a mesh in parallel
-from platform import java_ver
-import sys
-from tkinter import W
-import salome
-
-import time
-
-
-salome.salome_init()
-import salome_notebook
-notebook = salome_notebook.NoteBook()
-
-###
-### GEOM component
-###
-
-import GEOM
-from salome.geom import geomBuilder
-from salome.smesh import smeshBuilder
-import math
-import SALOMEDS
-
-import numpy as np
-
-geompy = geomBuilder.New()
-
-smesh = smeshBuilder.New()
-
-
-def build_seq_mesh(nbox, boxsize, offset):
- # Create 3D faces
- boxes = []
- # First creating all the boxes
- for i in range(nbox):
- for j in range(nbox):
- for k in range(nbox):
-
- x_orig = i*(boxsize+offset)
- y_orig = j*(boxsize+offset)
- z_orig = k*(boxsize+offset)
-
- tmp_box = geompy.MakeBoxDXDYDZ(boxsize, boxsize, boxsize)
-
- if not i == j == k == 0:
- box = geompy.MakeTranslation(tmp_box, x_orig,
- y_orig, z_orig)
- else:
- box = tmp_box
-
- geompy.addToStudy(box, 'box_{}:{}:{}'.format(i, j, k))
-
- boxes.append(box)
-
- # Create fuse of all boxes
- all_boxes = geompy.MakeCompound(boxes)
- geompy.addToStudy(all_boxes, 'Compound_1')
-
- # Removing duplicates faces and edges
- all_boxes = geompy.MakeGlueFaces(all_boxes, 1e-07)
- geompy.addToStudy(all_boxes, 'Glued_Faces_1')
-
- all_boxes = geompy.MakeGlueEdges(all_boxes, 1e-07)
- geompy.addToStudy(all_boxes, 'rubik_cube')
-
-
- # Building sequetial mesh
- print("Creating mesh")
- all_box_mesh = smesh.Mesh(all_boxes, "seq_mesh")
-
- print("Adding algo")
- algo3d = all_box_mesh.Tetrahedron(algo=smeshBuilder.NETGEN_1D2D3D)
-
- netgen_parameters = algo3d.Parameters()
- netgen_parameters.SetMaxSize(34.641)
- netgen_parameters.SetMinSize(0.141421)
- netgen_parameters.SetOptimize(1)
- netgen_parameters.SetCheckOverlapping(0)
- netgen_parameters.SetCheckChartBoundary(0)
- netgen_parameters.SetFineness(5)
- netgen_parameters.SetNbSegPerEdge(16*(boxsize//100))
- netgen_parameters.SetNbSegPerRadius(1.5)
- netgen_parameters.SetGrowthRate(0.15)
- netgen_parameters.SetChordalError(-1)
- netgen_parameters.SetChordalErrorEnabled(0)
- netgen_parameters.SetUseSurfaceCurvature(1)
- netgen_parameters.SetQuadAllowed(0)
- netgen_parameters.SetCheckOverlapping(False)
- netgen_parameters.SetNbThreads(2)
-
- return all_boxes, all_box_mesh, netgen_parameters
-
-def run_test(nbox=2, boxsize=100):
- """ Run sequential mesh and parallel version of it
-
- nbox: NUmber of boxes
- boxsize: Size of each box
- """
- geom, seq_mesh, netgen_parameters = build_seq_mesh(nbox, boxsize, 0)
-
- par_mesh = smesh.ParallelMesh(geom, netgen_parameters, 6, name="par_mesh")
-
- start = time.monotonic()
- is_done = seq_mesh.Compute()
- assert is_done
- stop = time.monotonic()
- time_seq = stop-start
-
- start = time.monotonic()
- is_done = par_mesh.Compute()
- assert is_done
- stop = time.monotonic()
- time_par = stop-start
-
- print(" Tetrahedron: ", seq_mesh.NbTetras(), par_mesh.NbTetras())
- print(" Triangle: ", seq_mesh.NbTriangles(), par_mesh.NbTriangles())
- print(" edge: ", seq_mesh.NbEdges(), par_mesh.NbEdges())
-
- assert par_mesh.NbTetras() > 0
- assert par_mesh.NbTriangles() > 0
- assert par_mesh.NbEdges() > 0
-
- print("Time elapsed (seq, par): ", time_seq, time_par)
-
-def main():
- if sys.platform == "win32":
- print("Test disabled on Windows")
- return
- nbox = 2
- boxsize = 100
- run_test(nbox, boxsize)
-
-main()
SMESH_create_dual_mesh_adapt.py
SMESH_create_dual_mesh_tpipe.py
netgen_runner.py
- SMESH_ParallelCompute.py
)
IF(NOT WIN32)
LIST(APPEND BAD_TESTS