From 8606805252362caea2274a0fe99ecf46edfef3de Mon Sep 17 00:00:00 2001 From: Christophe Bourcier Date: Wed, 2 Nov 2022 16:49:55 +0100 Subject: [PATCH 1/4] Improve Top-ii-Vol dialog box layout And add CEA to copyright --- .../TopIIVolMeshPlug/TopIIVolMeshMonitor.py | 2 +- .../TopIIVolMeshPluginDialog.py | 3 +- .../TopIIVolMeshPluginDialog.ui | 845 ++++++++---------- .../TopIIVolMeshPlugin_plugin.py | 2 +- 4 files changed, 391 insertions(+), 461 deletions(-) diff --git a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshMonitor.py b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshMonitor.py index e3ff5076c..29508910f 100644 --- a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshMonitor.py +++ b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshMonitor.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2013-2022 EDF R&D +# Copyright (C) 2013-2022 CEA/DES, EDF R&D # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public diff --git a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py index 73b5fc7d2..4e370d04e 100644 --- a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py +++ b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2013-2022 EDF R&D +# Copyright (C) 2013-2022 CEA/DES, EDF R&D # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public @@ -60,7 +60,6 @@ class TopIIVolMeshPluginDialog(Ui_TopIIVolMeshMainFrame,QWidget): self.qleTmpDir.setText(os.path.join('/tmp',getpass.getuser(),'top-ii-vol')) except: self.qleTmpDir.setText('/tmp') - self.resize(800, 500) self.outputMesh = '' def OnQpbHelpClicked(self): diff --git a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui index c148582f6..b046f0eb5 100644 --- a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui +++ b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui @@ -6,469 +6,400 @@ 0 0 - 780 - 411 + 663 + 298 Tetra Mesh from cloud of xyz points mesh generator - - - - 10 - 10 - 761 - 101 - - - - - 10 - - - - Input Mesh - - - - - 10 - 50 - 151 - 31 - - - - - 10 - - - - DEM input file - - - - 18 - 18 - - - - - - - 170 - 50 - 531 - 31 - - - - - 10 - - - - - - - - 10 - 120 - 761 - 231 - - - - Options - - - - - 10 - 30 - 62 - 22 - - - - 0 - - - 999999999 - - - 10 - - - - - - 80 - 30 - 201 - 20 - - - - Number of points in X direction - - - - - - 10 - 70 - 62 - 22 - - - - 0 - - - 999999999 - - - 10 - - - - - - 10 - 110 - 62 - 22 - - - - 0 - - - 999999999 - - - 10 - - - - - - 80 - 70 - 211 - 20 - - - - Number of points in Y direction - - - - - - 80 - 110 - 211 - 20 - - - - Number of points in Z direction - - - - - - 10 - 150 - 62 - 22 - - - - -999999999 - - - 999999999 - - - 0 - - - - - - 80 - 150 - 201 - 20 - - - - Depth in Z direction - - - - - - 630 - 30 - 91 - 21 - - - - - - - - - - 370 - 30 - 151 - 16 - - - - Number of processors - - - - - - 660 - 30 - 101 - 16 - - - - Distributed - - - - - - 370 - 70 - 261 - 16 - - - - Number of partitions in X direction - - - - - - 370 - 110 - 251 - 16 - - - - Number of partitions in Y direction - - - - - - 370 - 150 - 251 - 16 - - - - Number of partitions in Z direction - - - - - - 300 - 30 - 62 - 22 - - - - 0 - - - 999999999 - - - 1 - - - - - - 300 - 70 - 62 - 22 - - - - 0 - - - 999999999 - - - 1 - - - - - - 300 - 110 - 62 - 22 - - - - 0 - - - 999999999 - - - 1 - - - - - - 300 - 150 - 62 - 22 - - - - 0 - - - 999999999 - - - 1 - - - - - - 10 - 200 - 611 - 23 - - - - - - - - - - 10 - 180 - 391 - 16 - - - - Workspace - - - - - - 630 - 70 - 91 - 21 - - - - - - - - - - 660 - 70 - 101 - 16 - - - - Display mesh - - - - - - - 10 - 370 - 761 - 27 - - - - - - - Compute - - - - - - - Close - - - - - - - Qt::Horizontal - - - - 40 - 20 - - - - - - - - - 10 - - - - Help - - - - - + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + 10 + + + + Input Mesh + + + + + + + 10 + + + + + + + + + 10 + + + + DEM input file + + + + 18 + 18 + + + + + + + + + + + Qt::Vertical + + + + 20 + 40 + + + + + + + + + + Compute + + + + + + + Close + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + 10 + + + + Help + + + + + + + + + Options + + + + + + 0 + + + 999999999 + + + 10 + + + + + + + Number of points in X direction + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + + + + + + + + Distributed + + + + + + + Qt::Horizontal + + + + 40 + 20 + + + + + + + + 0 + + + 999999999 + + + 1 + + + + + + + Number of processors + + + + + + + Qt::Horizontal + + + + 45 + 20 + + + + + + + + 0 + + + 999999999 + + + 10 + + + + + + + Number of points in Y direction + + + + + + + + + + + + + + Display mesh + + + + + + + 0 + + + 999999999 + + + 1 + + + + + + + Number of partitions in X direction + + + + + + + 0 + + + 999999999 + + + 10 + + + + + + + Number of points in Z direction + + + + + + + 0 + + + 999999999 + + + 1 + + + + + + + Number of partitions in Y direction + + + + + + + -999999999 + + + 999999999 + + + 0 + + + + + + + Depth in Z direction + + + + + + + 0 + + + 999999999 + + + 1 + + + + + + + Number of partitions in Z direction + + + + + + + Workspace + + + + + + + + 0 + 0 + + + + + + + + + + + + + qpbMeshFile + qleMeshFile + qsbXPoints + qsbYPoints + qsbZPoints + qsbDepth + qcbDistributed + qsbNBprocs + qsbXParts + qsbYParts + qsbZParts + qcbDisplayMesh + qleTmpDir + qpbCompute + qpbClose + qpbHelp + diff --git a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPlugin_plugin.py b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPlugin_plugin.py index a7da12718..0db8f9d3c 100644 --- a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPlugin_plugin.py +++ b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPlugin_plugin.py @@ -1,5 +1,5 @@ # -*- coding: utf-8 -*- -# Copyright (C) 2013-2022 EDF R&D +# Copyright (C) 2013-2022 CEA/DES, EDF R&D # # This library is free software; you can redistribute it and/or # modify it under the terms of the GNU Lesser General Public From 255c7387996a2d17abc97fdeb92f03f8c9b8110f Mon Sep 17 00:00:00 2001 From: Afeef Date: Thu, 3 Nov 2022 11:52:23 +0100 Subject: [PATCH 2/4] Better layout with documentation update Thanks to Christophe --- .../TopIIVolMeshPluginDialog.py | 40 +- .../TopIIVolMeshPluginDialog.ui | 374 ++++++++++-------- .../TopIIVolMeshPlug/doc/TopIIVolMesh.rst | 29 +- .../doc/images/callTopIIVolMesh.png | Bin 30670 -> 90435 bytes src/Tools/TopIIVolMeshPlug/doc/index.rst | 2 +- 5 files changed, 254 insertions(+), 191 deletions(-) diff --git a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py index 4e370d04e..122c90e80 100644 --- a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py +++ b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.py @@ -48,13 +48,9 @@ class TopIIVolMeshPluginDialog(Ui_TopIIVolMeshMainFrame,QWidget): self.qpbMeshFile.clicked.connect(self.OnQpbMeshFileClicked) self.qpbMeshFile.setToolTip("Select input DEM file") self.qpbClose.clicked.connect(self.OnQpbCloseClicked) - self.qcbDistributed.stateChanged[int].connect(self.OnqcbDistributedClicked) - self.qlbXParts.setVisible(False) - self.qlbYParts.setVisible(False) - self.qlbZParts.setVisible(False) - self.qsbXParts.setVisible(False) - self.qsbYParts.setVisible(False) - self.qsbZParts.setVisible(False) + self.qrbDist.clicked.connect(self.OnqrbDistClicked) + self.qrbPar.clicked.connect(self.OnqrbParClicked) + self.qrbSeq.clicked.connect(self.OnqrbSeqClicked) self.SALOME_TMP_DIR = None try: self.qleTmpDir.setText(os.path.join('/tmp',getpass.getuser(),'top-ii-vol')) @@ -91,7 +87,7 @@ class TopIIVolMeshPluginDialog(Ui_TopIIVolMeshMainFrame,QWidget): zPoints = self.qsbZPoints.value() depth = self.qsbDepth.value() nProcs = self.qsbNBprocs.value() - if not self.qcbDistributed.isChecked(): + if not self.qrbDist.isChecked(): if nProcs == 1: shellCmd = "topIIvol_Mesher" else: @@ -121,18 +117,30 @@ class TopIIVolMeshPluginDialog(Ui_TopIIVolMeshMainFrame,QWidget): pathlib.Path(self.SALOME_TMP_DIR).mkdir(parents=True, exist_ok=True) self.outputMesh= os.path.join(self.SALOME_TMP_DIR, inputMesh.split('/').pop().replace('.xyz','.mesh')) shellCmd+= " --out " + self.outputMesh + os.chdir(self.SALOME_TMP_DIR) print("INFO: ", shellCmd) myMonitorView=TopIIVolMeshMonitor(self, shellCmd) - def OnqcbDistributedClicked(self): - state = self.qcbDistributed.isChecked() - self.qlbXParts.setVisible(state) - self.qlbYParts.setVisible(state) - self.qlbZParts.setVisible(state) - self.qsbXParts.setVisible(state) - self.qsbYParts.setVisible(state) - self.qsbZParts.setVisible(state) + def OnqrbDistClicked(self): + state = self.qrbDist.isChecked() + self.qgbDist.setEnabled(state) + self.qsbNBprocs.setEnabled(state) + self.qlbNBprocs.setEnabled(state) + def OnqrbParClicked(self): + state = self.qrbPar.isChecked() + self.qgbDist.setEnabled(not state) + self.qsbNBprocs.setEnabled(state) + self.qlbNBprocs.setEnabled(state) + + def OnqrbSeqClicked(self): + state = self.qrbSeq.isChecked() + if state: + self.qsbNBprocs.setValue(1) + self.qgbDist.setEnabled(not state) + self.qsbNBprocs.setEnabled(not state) + self.qlbNBprocs.setEnabled(not state) + def OnQpbCloseClicked(self): self.close() diff --git a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui index b046f0eb5..4a449f09e 100644 --- a/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui +++ b/src/Tools/TopIIVolMeshPlug/TopIIVolMeshPluginDialog.ui @@ -6,12 +6,12 @@ 0 0 - 663 - 298 + 758 + 400 - Tetra Mesh from cloud of xyz points mesh generator + Tetrahedral mesh generator for DEM point-clouds @@ -129,25 +129,74 @@ Options - - - - - 0 - - - 999999999 - - - 10 - - - - - - - Number of points in X direction + + + + + Number of points + + + + + 0 + + + 999999999 + + + 10 + + + + + + + X direction + + + + + + + 0 + + + 999999999 + + + 10 + + + + + + + Y direction + + + + + + + 0 + + + 999999999 + + + 10 + + + + + + + Z direction + + + + @@ -157,41 +206,63 @@ - 40 + 0 20 - - - - + + + + Meshing + + + + + Sequential + + + true + + + + + + + Parallel + + + + + + + Parallel distributed + + + + - - - - Distributed - - - - - + + Qt::Horizontal - 40 + 0 20 - + + + false + 0 @@ -203,121 +274,92 @@ - - + + + + false + Number of processors - - - - Qt::Horizontal + + + + false - - - 45 - 20 - + + Number of partitions - - - - - - 0 - - - 999999999 - - - 10 - - - - - - - Number of points in Y direction - - - - - - - - - - - - - - Display mesh - - - - - - - 0 - - - 999999999 - - - 1 - - - - - - - Number of partitions in X direction + + false + + + + + 0 + + + 999999999 + + + 1 + + + + + + + Y direction + + + + + + + X direction + + + + + + + Z direction + + + + + + + 0 + + + 999999999 + + + 1 + + + + + + + 0 + + + 999999999 + + + 1 + + + + - - - 0 - - - 999999999 - - - 10 - - - - - - - Number of points in Z direction - - - - - - - 0 - - - 999999999 - - - 1 - - - - - - - Number of partitions in Y direction - - - - -999999999 @@ -330,41 +372,51 @@ - + Depth in Z direction - - - - 0 - - - 999999999 - - - 1 - - - - - + + - Number of partitions in Z direction + + + + true - + + + + Display mesh + + + + + + + Qt::Horizontal + + + + 60 + 20 + + + + + Workspace - + @@ -389,12 +441,10 @@ qsbYPoints qsbZPoints qsbDepth - qcbDistributed qsbNBprocs qsbXParts qsbYParts qsbZParts - qcbDisplayMesh qleTmpDir qpbCompute qpbClose diff --git a/src/Tools/TopIIVolMeshPlug/doc/TopIIVolMesh.rst b/src/Tools/TopIIVolMeshPlug/doc/TopIIVolMesh.rst index 48e3f873a..b9d871d31 100644 --- a/src/Tools/TopIIVolMeshPlug/doc/TopIIVolMesh.rst +++ b/src/Tools/TopIIVolMeshPlug/doc/TopIIVolMesh.rst @@ -1,7 +1,7 @@ Introduction ============ -**topIIvol** meshing tool provides sequential/parallel tools for creating volumetric tetrahedral meshes from a given topology (point-cloud `*.xyz`). +**topIIvol** meshing tool provides sequential and parallel tools for creating volumetric tetrahedral meshes from a given terrain topology via digital elevation model (DEM point-cloud `*.xyz`). Via this plugin one could produce distributed meshes suitable for domain-decomposition based solvers or simply non distributed meshes (single mesh) suitable for a sequential/parallel solver. Running topIIvol Plug-in ======================== @@ -15,49 +15,54 @@ Running topIIvol Plug-in **topIIVolMesh** Options ======================== +Users have option of performing meshing via: + +- *Sequential* mode: mesh computation in sequential and outputs a single mesh. +- *Parallel* mode: mesh computation in parallel and outputs a single mesh. +- *Parallel distributed* mode: mesh computation in parallel and outputs partitioned meshes. Sequential mode --------------- -If the number of processors is set to 1, **topIIvol_Mesher** sequential tool is called for creating volumetric tetrahedral meshes from a given topology. The volumetric mesh can be displayed in SALOME by ticking the "Display mesh" check-box. +By default sequential meshing mode is activated. **topIIvol_Mesher** sequential tool is called for creating volumetric tetrahedral mesh for the given DEM point-cloud. The volumetric mesh can be displayed in SALOME by ticking the "Display mesh" check-box. The list of input parameters are: -- DEM input file: input point cloud file; +- DEM input file: input point cloud file in .xyz format; - Number of X points present in the input point cloud; - Number of Y points present in the input point cloud; -- Number of Z points intended in the z direction; +- Number of Z points intended in the Z direction; - Depth of the mesh needed; - temporary directory for calculation. Parallel mode --------------- -If the number of processors is greater than one, **topIIvol_ParMesher** parallel computing tool is called for creating volumetric tetrahedral meshes from a given topology. The volumetric mesh can be displayed in SALOME by ticking the "Display mesh" check-box. +For larger meshes the parallel meshing mode can be activated via the check-box **Parallel**. Additionally, this requires the user to provide the number of processors to be used for parallel meshing. Then, **topIIvol_ParMesher** parallel computing tool is called for creating volumetric tetrahedral mesh for the given DEM point-cloud. The volumetric mesh can be displayed in SALOME by ticking the "Display mesh" check-box. The list of input parameters are: -- DEM input file: input point cloud file; +- DEM input file: input point cloud file in .xyz format; - Number of X points present in the input point cloud; - Number of Y points present in the input point cloud; -- Number of Z points intended in the z direction; +- Number of Z points intended in the Z direction; - Depth of the mesh needed; - Number of MPI ranks - temporary directory for calculation. -Distributed mode +Parallel distributed mode ----------------- -If the check-box **Distributed** is ticked, **topIIvol_DistMesher** computing tool is called for creating embarassingly parallel distributed meshes from a given topology. +For larger meshes suitable for distributed-memory solvers (domain-decomposition) the distributed parallel meshing mode can be activated via the check-box **Parallel distributed**. This requires the user to provide the number of processors to be used for parallel meshing and how to partition the mesh in each direction (X, Y, Z). Then, **topIIvol_DistMesher** computing tool is called for creating embarassingly parallel distributed meshes for the given DEM point-cloud. These volumetric mesh partitions can be displayed in SALOME by ticking the "Display mesh" check-box. The list of input parameters are: -- DEM input file: input point cloud file; +- DEM input file: input point cloud file in .xyz format; - Number of X points present in the input point cloud; - Number of Y points present in the input point cloud; -- Number of Z points intended in the z direction; +- Number of Z points intended in the Z direction; +- Depth of the mesh needed; - Number of partitions in X direction; - Number of partitions in Y direction; - Number of partitions in Z direction; -- Depth of the mesh needed; - Number of MPI ranks - temporary directory for calculation. diff --git a/src/Tools/TopIIVolMeshPlug/doc/images/callTopIIVolMesh.png b/src/Tools/TopIIVolMeshPlug/doc/images/callTopIIVolMesh.png index 72a9d5d943588e8ebcd428e986df54e48f6fc7b0..867b73af298196fb0ec06955dd083907f307d205 100644 GIT binary patch literal 90435 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 MKA(4T?w8yC7uHuBb^rhX diff --git a/src/Tools/TopIIVolMeshPlug/doc/index.rst b/src/Tools/TopIIVolMeshPlug/doc/index.rst index 3cd237947..a54ffdb8a 100644 --- a/src/Tools/TopIIVolMeshPlug/doc/index.rst +++ b/src/Tools/TopIIVolMeshPlug/doc/index.rst @@ -8,7 +8,7 @@ topIIvol plugin documentation This documentation covers the usage of **top-ii-vol** as plug-in in SALOME that can be used within the SALOME Mesh module. -TopIIVolMesh plug-in uses CEA **top-ii-Vol** meshing tool,which provides sequential/parallel tools for creating volumetric tetrahedral meshes from a given topology. +TopIIVolMesh plug-in uses CEA **top-ii-Vol** meshing tool, which provides sequential and parallel tools for creating volumetric tetrahedral meshes for a given terrain topology. This plug-in offers only the most common functionalities of the tool. Contents: From f6a8df1d49b9a429efd8c7042fe4ee53ec7680bc Mon Sep 17 00:00:00 2001 From: Yoann Audouin Date: Wed, 2 Nov 2022 10:51:17 +0100 Subject: [PATCH 3/4] Revert "Corrections for compilation on other OS" This reverts commit df57f987dd5df72834dd8d1b8647a275123f7465. --- src/SMESH/SMESH_Gen.cxx | 4 ++-- src/SMESH_I/SMESH_Mesh_i.hxx | 1 + 2 files changed, 3 insertions(+), 2 deletions(-) diff --git a/src/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index 0d59428af..2a7e23af9 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -28,7 +28,6 @@ //#define CHRONODEF -#include #include "SMESH_Gen.hxx" #include "SMESH_DriverMesh.hxx" @@ -59,6 +58,7 @@ using namespace std; #include +#include namespace fs = boost::filesystem; // Environment variable separator @@ -240,7 +240,7 @@ const std::function - compute_function([] (SMESH_subMesh* sm, + compute_function([&] (SMESH_subMesh* sm, SMESH_subMesh::compute_event event, SMESH_subMesh *shapeSM, bool aShapeOnly, diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index 25892ca9d..444c7b791 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -674,6 +674,7 @@ private: const bool theIsDump); void SetNbThreads(int nbThreads); + void SetMesherNbThreads(int nbThreads); /*! * \brief Finds concurrent sub-meshes From 5123821d4d502b36f36307b003e09ccf21ff11d8 Mon Sep 17 00:00:00 2001 From: Yoann Audouin Date: Wed, 2 Nov 2022 10:54:05 +0100 Subject: [PATCH 4/4] Revert "Merge branch 'yan/parallel_mesh2'" This reverts commit 4403c126a0d688d98888156656f1df387a1b1dee, reversing changes made to 4dc895105ab7686df2e2987d35d46a4e379ea707. --- doc/gui/input/about_meshes.rst | 2 +- idl/SMESH_Mesh.idl | 49 ++-- src/SMESH/CMakeLists.txt | 8 +- src/SMESH/SMESH_Algo.cxx | 20 +- src/SMESH/SMESH_Algo.hxx | 19 +- src/SMESH/SMESH_DriverMesh.cxx | 104 ------- src/SMESH/SMESH_DriverMesh.hxx | 45 --- src/SMESH/SMESH_DriverShape.cxx | 179 ------------ src/SMESH/SMESH_DriverShape.hxx | 39 --- src/SMESH/SMESH_Gen.cxx | 269 +++-------------- src/SMESH/SMESH_Gen.hxx | 30 +- src/SMESH/SMESH_Mesh.cxx | 20 +- src/SMESH/SMESH_Mesh.hxx | 81 ++--- src/SMESH/SMESH_MeshLocker.cxx | 46 --- src/SMESH/SMESH_MeshLocker.hxx | 44 --- src/SMESH/SMESH_MesherHelper.cxx | 90 +++--- src/SMESH/SMESH_subMesh.cxx | 32 +- src/SMESH/SMESH_subMesh.hxx | 17 +- src/SMESHDS/SMESHDS_Mesh.cxx | 358 +++++++++++------------ src/SMESH_I/SMESH_2smeshpy.cxx | 3 +- src/SMESH_I/SMESH_Gen_i.cxx | 4 +- src/SMESH_I/SMESH_Mesh_i.cxx | 18 +- src/SMESH_I/SMESH_Mesh_i.hxx | 7 +- src/SMESH_SWIG/smeshBuilder.py | 131 +-------- src/StdMeshers/StdMeshers_Regular_1D.cxx | 6 +- test/SMESH_ParallelCompute.py | 131 --------- test/netgen_runner.py | 129 -------- test/tests.set | 2 - 28 files changed, 382 insertions(+), 1501 deletions(-) delete mode 100644 src/SMESH/SMESH_DriverMesh.cxx delete mode 100644 src/SMESH/SMESH_DriverMesh.hxx delete mode 100644 src/SMESH/SMESH_DriverShape.cxx delete mode 100644 src/SMESH/SMESH_DriverShape.hxx delete mode 100644 src/SMESH/SMESH_MeshLocker.cxx delete mode 100644 src/SMESH/SMESH_MeshLocker.hxx delete mode 100644 test/SMESH_ParallelCompute.py delete mode 100644 test/netgen_runner.py diff --git a/doc/gui/input/about_meshes.rst b/doc/gui/input/about_meshes.rst index 619bd799f..73af1714e 100644 --- a/doc/gui/input/about_meshes.rst +++ b/doc/gui/input/about_meshes.rst @@ -52,7 +52,7 @@ The mesh can include the following entities: * **Node** - a mesh entity defining a position in 3D space with coordinates (x, y, z). * **Edge** (or segment) - 1D mesh element linking two nodes. * **Face** - 2D mesh element representing a part of surface bound by links between face nodes. A face can be a triangle, quadrangle or polygon. -* **Volume** - 3D mesh element representing a part of 3D space bound by volume facets. Nodes of a volume describing each facet are defined by the :ref:`connectivity convention `. A volume can be a tetrahedron, hexahedron, pentahedron, pyramid, hexagonal or polyhedron. +* **Volume** - 3D mesh element representing a part of 3D space bound by volume facets. Nodes of a volume describing each facet are defined by the :ref:`connectivity convention `. A volume can be a tetrahedron, hexahedron, pentahedron, pyramid, hexagonal prism or polyhedron. * **0D** element - mesh element defined by one node. * **Ball** element - discrete mesh element defined by a node and a diameter. diff --git a/idl/SMESH_Mesh.idl b/idl/SMESH_Mesh.idl index 7b86361d8..bfbb0cdd5 100644 --- a/idl/SMESH_Mesh.idl +++ b/idl/SMESH_Mesh.idl @@ -156,7 +156,7 @@ module SMESH Geom_BALL, Geom_LAST }; - + /*! * ElementOrder points out entities of what order are requested */ @@ -238,7 +238,7 @@ module SMESH DRS_FAIL // general failure (exception etc.) }; - /*! + /*! * \brief A structure containing information about MED file */ struct MedFileInfo @@ -263,7 +263,7 @@ module SMESH */ const long EXTRUSION_FLAG_BOUNDARY = 1; const long EXTRUSION_FLAG_SEW = 2; - + /*! * Structure used in mesh edit preview data (MeshPreviewStruct) */ @@ -344,7 +344,7 @@ module SMESH /*! * Get geom shape to mesh. A result should not be nil. Use HasShapeToMesh() - * to know if a returned shape + * to know if a returned shape */ GEOM::GEOM_Object GetShapeToMesh() raises (SALOME::SALOME_Exception); @@ -457,7 +457,7 @@ module SMESH in SMESH_GroupBase aGroup2, in string name ) raises (SALOME::SALOME_Exception); - + /*! * Union of list of groups * New group is created. All mesh elements that are @@ -476,7 +476,7 @@ module SMESH in SMESH_GroupBase aGroup2, in string name ) raises (SALOME::SALOME_Exception); - + /*! * Intersection of list of groups * New group is created. All mesh elements that are @@ -495,7 +495,7 @@ module SMESH in SMESH_GroupBase aToolGroup, in string name ) raises (SALOME::SALOME_Exception); - + /*! * Cut of lists of groups * New group is created. All mesh elements that are present in @@ -505,14 +505,14 @@ module SMESH in ListOfGroups aToolGroups, in string name) raises (SALOME::SALOME_Exception); - + /*! * Create a group of entities basing on nodes of other groups. * \param [in] aListOfGroups - list of either groups, sub-meshes or filters. * \param [in] anElemType - a type of elements to include to the new group. * \param [in] name - a name of the new group. * \param [in] nbCommonNodes - criterion of inclusion of an element to the new group. - * \param [in] underlyingOnly - if \c True, an element is included to the + * \param [in] underlyingOnly - if \c True, an element is included to the * new group provided that it is based on nodes of an element of * \a aListOfGroups * \return SMESH_Group - the created group @@ -679,12 +679,12 @@ module SMESH * med files in 4.0.0 (default format) or 3.2.1 or 3.3.1 formats. * The minor must be between 0 and the current minor version of MED file library. * If version is equal to -1, the version is not changed (default). - * - autoDimension : if @c True, a space dimension for export is defined by mesh + * - autoDimension : if @c True, a space dimension for export is defined by mesh * configuration; for example a planar mesh lying on XOY plane - * will be exported as a mesh in 2D space. + * will be exported as a mesh in 2D space. * If @a autoDimension == @c False, the space dimension is 3. * - fields : list of GEOM fields defined on the shape to mesh. - * - geomAssocFields : each character of this string means a need to export a + * - geomAssocFields : each character of this string means a need to export a * corresponding field; correspondence between fields and characters is following: * - 'v' stands for _vertices_ field; * - 'e' stands for _edges_ field; @@ -724,7 +724,7 @@ module SMESH * encoded in 10*major+minor (for instance, code for med 3.2.1 is 32) */ long_array GetMEDVersionsCompatibleForAppend(); - + /*! * Export Mesh to different Formats * (UNV supported version is I-DEAS 10) @@ -735,17 +735,17 @@ module SMESH in boolean renumer ) raises (SALOME::SALOME_Exception); void ExportSTL( in string file, in boolean isascii ) raises (SALOME::SALOME_Exception); - void ExportCGNS( in SMESH_IDSource meshPart, + void ExportCGNS( in SMESH_IDSource meshPart, in string file, in boolean overwrite, in boolean groupElemsByType) raises (SALOME::SALOME_Exception); - void ExportGMF( in SMESH_IDSource meshPart, + void ExportGMF( in SMESH_IDSource meshPart, in string file, in boolean withRequiredGroups) raises (SALOME::SALOME_Exception); - void ExportPartToDAT( in SMESH_IDSource meshPart, + void ExportPartToDAT( in SMESH_IDSource meshPart, in string file, in boolean renumer ) raises (SALOME::SALOME_Exception); - void ExportPartToUNV( in SMESH_IDSource meshPart, + void ExportPartToUNV( in SMESH_IDSource meshPart, in string file, in boolean renumer ) raises (SALOME::SALOME_Exception); void ExportPartToSTL( in SMESH_IDSource meshPart, @@ -857,10 +857,10 @@ module SMESH smIdType_array GetNodesId() raises (SALOME::SALOME_Exception); - + /*! * Returns type of mesh element - */ + */ ElementType GetElementType( in smIdType id, in boolean iselem ) raises (SALOME::SALOME_Exception); @@ -875,7 +875,7 @@ module SMESH smIdType_array GetSubMeshNodesId(in long ShapeID, in boolean all ) raises (SALOME::SALOME_Exception); - + ElementType GetSubMeshElementType(in long ShapeID) raises (SALOME::SALOME_Exception); @@ -899,11 +899,6 @@ module SMESH */ boolean SetMeshOrder(in submesh_array_array theSubMeshArray); - /*! - * \brief Set Number of Threads - */ - void SetNbThreads(in long nbThreads); - /*! /*! * Get mesh description @@ -944,7 +939,7 @@ module SMESH long GetShapeID(in smIdType id); /*! - * For given element returns ID of result shape after + * For given element returns ID of result shape after * ::FindShape() from SMESH_MeshEditor * If there is not element for given ID - returns -1 */ @@ -1077,7 +1072,7 @@ module SMESH */ smIdType_array GetElementsByType( in ElementType theType ) raises (SALOME::SALOME_Exception); - + /*! * Returns type of mesh element (same as SMESH_Mesh::GetElementType() ) */ diff --git a/src/SMESH/CMakeLists.txt b/src/SMESH/CMakeLists.txt index 88d42d875..7929c74f8 100644 --- a/src/SMESH/CMakeLists.txt +++ b/src/SMESH/CMakeLists.txt @@ -90,9 +90,6 @@ SET(SMESHimpl_HEADERS SMESH_SMESH.hxx MG_ADAPT.hxx SMESH_Homard.hxx - SMESH_DriverMesh.hxx - SMESH_DriverShape.hxx - SMESH_MeshLocker.hxx ) # --- sources --- @@ -113,9 +110,6 @@ SET(SMESHimpl_SOURCES SMESH_MesherHelper.cxx MG_ADAPT.cxx SMESH_Homard.cxx - SMESH_DriverMesh.cxx - SMESH_DriverShape.cxx - SMESH_MeshLocker.cxx ) # --- rules --- @@ -123,7 +117,7 @@ SET(SMESHimpl_SOURCES ADD_LIBRARY(SMESHimpl ${SMESHimpl_SOURCES}) IF(WIN32) TARGET_COMPILE_OPTIONS(SMESHimpl PRIVATE /bigobj) - ADD_DEFINITIONS(-DNOMINMAX) + ADD_DEFINITIONS(-DNOMINMAX) ENDIF(WIN32) TARGET_LINK_LIBRARIES(SMESHimpl ${_link_LIBRARIES} ) diff --git a/src/SMESH/SMESH_Algo.cxx b/src/SMESH/SMESH_Algo.cxx index 582e554ee..788a048c1 100644 --- a/src/SMESH/SMESH_Algo.cxx +++ b/src/SMESH/SMESH_Algo.cxx @@ -169,7 +169,7 @@ const SMESH_Algo::Features& SMESH_Algo::GetFeatures( const std::string& algoType //============================================================================= /*! - * + * */ //============================================================================= @@ -186,7 +186,7 @@ SMESH_Algo::SMESH_Algo (int hypId, SMESH_Gen * gen) //============================================================================= /*! - * + * */ //============================================================================= @@ -198,7 +198,7 @@ SMESH_Algo::~SMESH_Algo() //============================================================================= /*! - * + * */ //============================================================================= @@ -238,7 +238,7 @@ istream & SMESH_Algo::LoadFrom(istream & load) { return load; } //============================================================================= /*! - * + * */ //============================================================================= @@ -252,7 +252,7 @@ const vector < string > &SMESH_Algo::GetCompatibleHypothesis() * List the hypothesis used by the algorithm associated to the shape. * Hypothesis associated to father shape -are- taken into account (see * GetAppliedHypothesis). Relevant hypothesis have a name (type) listed in - * the algorithm. This method could be surcharged by specific algorithms, in + * the algorithm. This method could be surcharged by specific algorithms, in * case of several hypothesis simultaneously applicable. */ //============================================================================= @@ -264,7 +264,7 @@ SMESH_Algo::GetUsedHypothesis(SMESH_Mesh & aMesh, { SMESH_Algo* me = const_cast< SMESH_Algo* >( this ); - std::list savedHyps; // don't delete the list if + std::list savedHyps; // don't delete the list if savedHyps.swap( me->_usedHypList ); // it does not change (#16578) me->_usedHypList.clear(); @@ -565,7 +565,7 @@ bool SMESH_Algo::IsStraight( const TopoDS_Edge & E, return false; // E seems closed double edgeTol = 10 * curve.Tolerance(); - double lenTol2 = lineLen2 * 1e-4; + double lenTol2 = lineLen2 * 1e-4; double tol2 = Min( edgeTol * edgeTol, lenTol2 ); const double nbSamples = 7; @@ -816,7 +816,7 @@ SMESH_Algo::EMeshError SMESH_Algo::GetMeshError(SMESH_subMesh* subMesh) /*! * \brief Sets event listener to submeshes if necessary * \param subMesh - submesh where algo is set - * + * * After being set, event listener is notified on each event of a submesh. * By default non listener is set */ @@ -1020,7 +1020,7 @@ void SMESH_Algo::addBadInputElements(const SMESHDS_SubMesh* sm, //============================================================================= /*! - * + * */ //============================================================================= @@ -1034,7 +1034,7 @@ void SMESH_Algo::addBadInputElements(const SMESHDS_SubMesh* sm, //============================================================================= /*! - * + * */ //============================================================================= diff --git a/src/SMESH/SMESH_Algo.hxx b/src/SMESH/SMESH_Algo.hxx index 580d73d68..3beb89ae1 100644 --- a/src/SMESH/SMESH_Algo.hxx +++ b/src/SMESH/SMESH_Algo.hxx @@ -198,15 +198,15 @@ class SMESH_EXPORT SMESH_Algo : public SMESH_Hypothesis /*! * \brief Return a list of compatible hypotheses used to mesh a shape - * \param aMesh - the mesh + * \param aMesh - the mesh * \param aShape - the shape * \param ignoreAuxiliary - do not include auxiliary hypotheses in the list * \retval const std::list - hypotheses list - * + * * List the hypothesis used by the algorithm associated to the shape. * Hypothesis associated to father shape -are- taken into account (see * GetAppliedHypothesis). Relevant hypothesis have a name (type) listed in - * the algorithm. This method could be surcharged by specific algorithms, in + * the algorithm. This method could be surcharged by specific algorithms, in * case of several hypothesis simultaneously applicable. */ virtual const std::list & @@ -277,13 +277,10 @@ public: // 6 - if algo !NeedDiscreteBoundary() but requires presence of // hypotheses of dimension to generate all-dimensional mesh. // This info is used not to issue warnings on hiding of lower global algos. - // - - virtual void setSubMeshesToCompute(SMESH_subMesh * aSubMesh) {SubMeshesToCompute().assign( 1, aSubMesh );} public: // ================================================================== - // Methods to track non hierarchical dependencies between submeshes + // Methods to track non hierarchical dependencies between submeshes // ================================================================== /*! @@ -295,7 +292,7 @@ public: * By default none listener is set */ virtual void SetEventListener(SMESH_subMesh* subMesh); - + /*! * \brief Allow algo to do something after persistent restoration * \param subMesh - restored submesh @@ -303,7 +300,7 @@ public: * This method is called only if a submesh has HYP_OK algo_state. */ virtual void SubmeshRestored(SMESH_subMesh* subMesh); - + public: // ================================================================== // Common algo utilities @@ -401,7 +398,7 @@ public: enum EMeshError { MEr_OK = 0, MEr_HOLES, MEr_BAD_ORI, MEr_EMPTY }; /*! - * \brief Finds topological errors of a sub-mesh + * \brief Finds topological errors of a sub-mesh */ static EMeshError GetMeshError(SMESH_subMesh* subMesh); @@ -437,7 +434,7 @@ protected: std::vector _compatibleHypothesis; std::list _usedHypList; std::list _assigedShapeList; // _usedHypList assigned to - + // Algo features influencing which Compute() and how is called: // in what turn and with what input shape. diff --git a/src/SMESH/SMESH_DriverMesh.cxx b/src/SMESH/SMESH_DriverMesh.cxx deleted file mode 100644 index 01cc5df4c..000000000 --- a/src/SMESH/SMESH_DriverMesh.cxx +++ /dev/null @@ -1,104 +0,0 @@ -// 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_DriverMesh.cxx -// Author : Yoann AUDOUIN, EDF -// Module : SMESH -// - -#include "utilities.h" - -#include "SMESH_DriverMesh.hxx" - -#include "SMESH_Mesh.hxx" -#include "SMESH_Gen.hxx" - -#include -#include - -using namespace MEDCoupling; - -/** - * @brief Compares the mesh from two mesh files (MED) - * - * @param mesh_file1 First file - * @param mesh_file2 Second file - * @param mesh_name Name of the mesh in the files - * - * @return true if the mesh within the files are identical - */ -bool diffMEDFile(const std::string mesh_file1, const std::string mesh_file2, const std::string mesh_name){ - MEDFileUMesh* medmesh1 = MEDFileUMesh::New(mesh_file1, mesh_name); - MEDFileUMesh* medmesh2 = MEDFileUMesh::New(mesh_file2, mesh_name); - MEDCouplingUMesh *m0_1=medmesh1->getMeshAtLevel(0,false); - MEDCouplingUMesh *m0_2=medmesh2->getMeshAtLevel(0,false); - return m0_1->isEqual(m0_2, 1e-12); -} - -std::string getMeshName(std::string mesh_file){ - // TODO: Memory leak but desctructor private check with AG - MEDFileUMesh * myMedMesh = MEDFileUMesh::New(mesh_file); - - return myMedMesh->getLevel0Mesh()->getName(); -} - -/** - * @brief Import a mesh from a mesh file (MED) into a SMESH_Mesh object - * - * @param mesh_file the file - * @param aMesh the object - * @param mesh_name the name of the mesh in the file - * - * @return error code - */ -int importMesh(const std::string mesh_file, SMESH_Mesh& aMesh){ - // TODO: change that as it depends on the language - std::string mesh_name = getMeshName(mesh_file); - MESSAGE("Importing mesh from " << mesh_file << " mesh " << mesh_name); - int ret = aMesh.MEDToMesh(mesh_file.c_str(), mesh_name.c_str()); - return ret; -} - -/** - * @brief Export the content of a SMESH_Mesh into a mesh file (MED) - * - * @param mesh_file the file - * @param aMesh the object - * @param mesh_name name of the mesh in the file - * - * @return error code - */ -int exportMesh(const std::string mesh_file, SMESH_Mesh& aMesh, const std::string mesh_name){ - - MESSAGE("Exporting mesh to " << mesh_file); - aMesh.ExportMED(mesh_file.c_str(), // theFile - mesh_name.c_str(), // theMeshName - false, // theAutoGroups - -1, // theVersion - nullptr, // theMeshPart - true, // theAutoDimension - true, // theAddODOnVertices - 1e-8, // theZTolerance - true // theSaveNumbers - ); - return true; -} diff --git a/src/SMESH/SMESH_DriverMesh.hxx b/src/SMESH/SMESH_DriverMesh.hxx deleted file mode 100644 index 370f99515..000000000 --- a/src/SMESH/SMESH_DriverMesh.hxx +++ /dev/null @@ -1,45 +0,0 @@ -// 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 : SMESH_DriverMesh.hxx -// Author : Yoann AUDOUIN, EDF -// Module : SMESH -// - -#ifndef _SMESH_DRIVERMESH_HXX_ -#define _SMESH_DRIVERMESH_HXX_ - -#include -#include - -class SMESH_Mesh; - -bool diffMEDFile(const std::string mesh_file1, - const std::string mesh_file2, - const std::string mesh_name); -int importMesh(const std::string mesh_file, - SMESH_Mesh& aMesh); -int exportMesh(const std::string mesh_file, - SMESH_Mesh& aMesh, - const std::string meshName); - -#endif diff --git a/src/SMESH/SMESH_DriverShape.cxx b/src/SMESH/SMESH_DriverShape.cxx deleted file mode 100644 index c9db8372e..000000000 --- a/src/SMESH/SMESH_DriverShape.cxx +++ /dev/null @@ -1,179 +0,0 @@ -// 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_DriverShape.cxx -// Author : Yoann AUDOUIN, EDF -// Module : SMESH -// - -#include -#include -#include "SMESH_DriverShape.hxx" - -// step include -#include -#include -#include - -// Brep include -#include -#include - -//Occ include -#include - -#include -#include -namespace fs = boost::filesystem; - -/** - * @brief Import the content of a shape file (STEP) into a TopDS_Shape object - * - * @param shape_file the shape file - * @param aShape the object - * - * @return error code - */ -int importSTEPShape(const std::string shape_file, TopoDS_Shape& aShape){ - - MESSAGE("Importing STEP shape from " << shape_file); - STEPControl_Reader reader; - // Forcing Unit in meter - Interface_Static::SetCVal("xstep.cascade.unit","M"); - Interface_Static::SetIVal("read.step.ideas", 1); - Interface_Static::SetIVal("read.step.nonmanifold", 1); - IFSelect_ReturnStatus aStat = reader.ReadFile(shape_file.c_str()); - if(aStat != IFSelect_RetDone){ - throw SALOME_Exception("Reading error for " + shape_file); - } - - int NbTrans = reader.TransferRoots(); - // There should be only one shape within the file - assert(NbTrans==1); - aShape = reader.OneShape(); - - return false; -} - -/** - * @brief Export the content of a TopoDS_Shape into a shape file (STEP) - * - * @param shape_file the shape file - * @param aShape the object - * - * @return error code - */ -int exportSTEPShape(const std::string shape_file, const TopoDS_Shape& aShape){ - - MESSAGE("Exporting STEP shape to " << shape_file); - - STEPControl_Writer aWriter; - // Forcing Unit in meter - Interface_Static::SetCVal("xstep.cascade.unit","M"); - Interface_Static::SetCVal("write.step.unit","M"); - Interface_Static::SetIVal("write.step.nonmanifold", 1); - - IFSelect_ReturnStatus aStat = aWriter.Transfer(aShape,STEPControl_AsIs); - if(aStat != IFSelect_RetDone){ - throw SALOME_Exception("Reading error for " + shape_file); - } - - aStat = aWriter.Write(shape_file.c_str()); - - if(aStat != IFSelect_RetDone){ - throw SALOME_Exception("Writing error for " + shape_file); - } - return aStat; -} - -/** - * @brief Import the content of a shape file (BREP) into a TopDS_Shape object - * - * @param shape_file the shape file - * @param aShape the object - * - * @return error code - */ -int importBREPShape(const std::string shape_file, TopoDS_Shape& aShape){ - - MESSAGE("Importing BREP shape from " << shape_file); - BRep_Builder builder; - BRepTools::Read(aShape, shape_file.c_str(), builder); - - return false; -} - -/** - * @brief Export the content of a TopoDS_Shape into a shape file (BREP) - * - * @param shape_file the shape file - * @param aShape the object - * - * @return error code - */ -int exportBREPShape(const std::string shape_file, const TopoDS_Shape& aShape){ - - MESSAGE("Exporting BREP shape to " << shape_file); - BRepTools::Write(aShape, shape_file.c_str()); - - return false; -} - -/** - * @brief Import the content of a shape file into a TopDS_Shape object - * - * @param shape_file the shape file - * @param aShape the object - * - * @return error code - */ -int importShape(const std::string shape_file, TopoDS_Shape& aShape){ - std::string type = fs::path(shape_file).extension().string(); - boost::algorithm::to_lower(type); - if (type == ".brep"){ - return importBREPShape(shape_file, aShape); - } else if (type == ".step"){ - return importSTEPShape(shape_file, aShape); - } else { - throw SALOME_Exception("Unknow format for importShape: " + type); - } -} - -/** - * @brief Import the content of a shape file into a TopDS_Shape object - * - * @param shape_file the shape file - * @param aShape the object - * - * @return error code - */ -int exportShape(const std::string shape_file, const TopoDS_Shape& aShape){ - std::string type = fs::path(shape_file).extension().string(); - boost::algorithm::to_lower(type); - if (type == ".brep"){ - return exportBREPShape(shape_file, aShape); - } else if (type == ".step"){ - return exportSTEPShape(shape_file, aShape); - } else { - throw SALOME_Exception("Unknow format for exportShape: " + type); - } -} diff --git a/src/SMESH/SMESH_DriverShape.hxx b/src/SMESH/SMESH_DriverShape.hxx deleted file mode 100644 index b9e3a360e..000000000 --- a/src/SMESH/SMESH_DriverShape.hxx +++ /dev/null @@ -1,39 +0,0 @@ -// 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 : SMESH_DriverShape.hxx -// Author : Yoann AUDOUIN, EDF -// Module : SMESH -// - -#ifndef _SMESH_DRIVERSHAPE_HXX_ -#define _SMESH_DRIVERSHAPE_HXX_ - -#include -#include - -class TopoDS_Shape; - -int importShape(const std::string shape_file, TopoDS_Shape& aShape); -int exportShape(const std::string shape_file, const TopoDS_Shape& aShape); - -#endif \ No newline at end of file diff --git a/src/SMESH/SMESH_Gen.cxx b/src/SMESH/SMESH_Gen.cxx index 2a7e23af9..ef42e33e0 100644 --- a/src/SMESH/SMESH_Gen.cxx +++ b/src/SMESH/SMESH_Gen.cxx @@ -30,7 +30,6 @@ #include "SMESH_Gen.hxx" -#include "SMESH_DriverMesh.hxx" #include "SMDS_Mesh.hxx" #include "SMDS_MeshElement.hxx" #include "SMDS_MeshNode.hxx" @@ -48,7 +47,6 @@ #include #include "memoire.h" -#include #ifdef WIN32 #include @@ -57,9 +55,6 @@ #include using namespace std; -#include -#include -namespace fs = boost::filesystem; // Environment variable separator #ifdef WIN32 @@ -160,208 +155,6 @@ SMESH_Mesh* SMESH_Gen::CreateMesh(bool theIsEmbeddedMode) return aMesh; } - -//============================================================================= -/*! - * Algo to run the computation of all the submeshes of a mesh in sequentila - */ -//============================================================================= - -bool SMESH_Gen::sequentialComputeSubMeshes( - 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) -{ - MESSAGE("Compute submeshes sequentialy"); - - bool ret = true; - - SMESH_subMeshIteratorPtr smIt; - SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape); - - smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst); - while ( smIt->more() ) - { - SMESH_subMesh* smToCompute = smIt->next(); - - // do not mesh vertices of a pseudo shape - const TopoDS_Shape& shape = smToCompute->GetSubShape(); - const TopAbs_ShapeEnum shapeType = shape.ShapeType(); - if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX ) - continue; - - // check for preview dimension limitations - if ( aShapesId && 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; - } - - if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) - { - if (_compute_canceled) - return false; - smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes )); - setCurrentSubMesh( smToCompute ); - smToCompute->ComputeStateEngine( computeEvent ); - setCurrentSubMesh( nullptr ); - smToCompute->SetAllowedSubShapes( nullptr ); - } - - // we check all the sub-meshes here and detect if any of them failed to compute - if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE && - ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape )))) - ret = false; - else if ( aShapesId ) - aShapesId->insert( smToCompute->GetId() ); - } - //aMesh.GetMeshDS()->Modified(); - return ret; - -}; - -//============================================================================= -/* - * compute of a submesh - * This function is passed to the thread pool - */ -//============================================================================= -const std::function - compute_function([&] (SMESH_subMesh* sm, - SMESH_subMesh::compute_event event, - SMESH_subMesh *shapeSM, - bool aShapeOnly, - TopTools_IndexedMapOfShape *allowedSubShapes, - TSetOfInt* aShapesId) -> void -{ - if (sm->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) - { - sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes )); - //setCurrentSubMesh( sm ); - sm->ComputeStateEngine(event); - //setCurrentSubMesh( nullptr ); - sm->SetAllowedSubShapes( nullptr ); - } - - if ( aShapesId ) - aShapesId->insert( sm->GetId() ); - -}); - -//============================================================================= -/*! - * Algo to run the computation of all the submeshes of a mesh in parallel - */ -//============================================================================= - -bool SMESH_Gen::parallelComputeSubMeshes( - 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) -{ - - bool ret = true; - - SMESH_subMeshIteratorPtr smIt; - SMESH_subMesh *shapeSM = aMesh.GetSubMesh(aShape); - - // Pool of thread for computation - // TODO: move when parallelMesh created - aMesh.InitPoolThreads(); - - TopAbs_ShapeEnum previousShapeType = TopAbs_VERTEX; - int nbThreads = aMesh.GetNbThreads(); - MESSAGE("Compute submeshes with threads: " << nbThreads); - - - smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst); - while ( smIt->more() ) - { - SMESH_subMesh* smToCompute = smIt->next(); - - // do not mesh vertices of a pseudo shape - const TopoDS_Shape& shape = smToCompute->GetSubShape(); - const TopAbs_ShapeEnum shapeType = shape.ShapeType(); - // Not doing in parallel 1D and 2D meshes - if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX ) - continue; - if(shapeType==TopAbs_FACE||shapeType==TopAbs_EDGE) - aMesh.SetNbThreads(0); - else - aMesh.SetNbThreads(nbThreads); - - - if (shapeType != previousShapeType) { - // Waiting for all threads for the previous type to end - aMesh.wait(); - - std::string file_name; - switch(previousShapeType){ - case TopAbs_FACE: - file_name = "Mesh2D.med"; - break; - case TopAbs_EDGE: - file_name = "Mesh1D.med"; - break; - case TopAbs_VERTEX: - file_name = "Mesh0D.med"; - break; - case TopAbs_SOLID: - default: - file_name = ""; - break; - } - if(file_name != "") - { - fs::path mesh_file = fs::path(aMesh.tmp_folder) / fs::path(file_name); - exportMesh(mesh_file.string(), aMesh, "MESH"); - - } - //Resetting threaded pool info - previousShapeType = shapeType; - } - - // check for preview dimension limitations - if ( aShapesId && 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, - shapeSM, aShapeOnly, allowedSubShapes, - aShapesId)); - } - - // Waiting for the thread for Solids to finish - aMesh.wait(); - - aMesh.GetMeshDS()->Modified(); - - return ret; -}; - - //============================================================================= /* * Compute a mesh @@ -408,33 +201,57 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, // =============================================== // 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); + smIt = shapeSM->getDependsOnIterator(includeSelf, !complexShapeFirst); + while ( smIt->more() ) + { + SMESH_subMesh* smToCompute = smIt->next(); + + // do not mesh vertices of a pseudo shape + const TopoDS_Shape& shape = smToCompute->GetSubShape(); + const TopAbs_ShapeEnum shapeType = shape.ShapeType(); + if ( !aMesh.HasShapeToMesh() && shapeType == TopAbs_VERTEX ) + continue; + + // check for preview dimension limitations + if ( aShapesId && 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; + } + + if (smToCompute->GetComputeState() == SMESH_subMesh::READY_TO_COMPUTE) + { + if (_compute_canceled) + return false; + smToCompute->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes )); + setCurrentSubMesh( smToCompute ); + smToCompute->ComputeStateEngine( computeEvent ); + setCurrentSubMesh( nullptr ); + smToCompute->SetAllowedSubShapes( nullptr ); + } + + // we check all the sub-meshes here and detect if any of them failed to compute + if (smToCompute->GetComputeState() == SMESH_subMesh::FAILED_TO_COMPUTE && + ( shapeType != TopAbs_EDGE || !SMESH_Algo::isDegenerated( TopoDS::Edge( shape )))) + ret = false; + else if ( aShapesId ) + aShapesId->insert( smToCompute->GetId() ); + } + //aMesh.GetMeshDS()->Modified(); return ret; } else { // ================================================================ - // Apply algos that do NOT require discretized boundaries + // Apply algos that do NOT require discreteized boundaries // ("all-dimensional") and do NOT support sub-meshes, starting from // the most complex shapes and collect sub-meshes with algos that // DO support sub-meshes // ================================================================ + list< SMESH_subMesh* > smWithAlgoSupportingSubmeshes[4]; // for each dim // map to sort sm with same dim algos according to dim of @@ -631,7 +448,6 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, sm->SetAllowedSubShapes( fillAllowed( shapeSM, aShapeOnly, allowedSubShapes )); setCurrentSubMesh( sm ); sm->ComputeStateEngine( computeEvent ); - setCurrentSubMesh( NULL ); sm->SetAllowedSubShapes( nullptr ); if ( aShapesId ) @@ -644,7 +460,6 @@ bool SMESH_Gen::Compute(SMESH_Mesh & aMesh, // mesh the rest sub-shapes starting from vertices // ----------------------------------------------- ret = Compute( aMesh, aShape, aFlags | UPWARD, aDim, aShapesId, allowedSubShapes ); - } MEMOSTAT; @@ -788,7 +603,7 @@ bool SMESH_Gen::Evaluate(SMESH_Mesh & aMesh, const TopoDS_Shape& aSubShape = smToCompute->GetSubShape(); const int aShapeDim = GetShapeDim( aSubShape ); if ( aShapeDim < 1 ) break; - + SMESH_Algo* algo = GetAlgo( smToCompute ); if ( algo && !algo->NeedDiscreteBoundary() ) { if ( algo->SupportSubmeshes() ) { diff --git a/src/SMESH/SMESH_Gen.hxx b/src/SMESH/SMESH_Gen.hxx index 94058184e..b8b98a8a8 100644 --- a/src/SMESH/SMESH_Gen.hxx +++ b/src/SMESH/SMESH_Gen.hxx @@ -34,7 +34,6 @@ #include "SMESH_Algo.hxx" #include "SMESH_ComputeError.hxx" -#include "SMESH_subMesh.hxx" #include #include @@ -42,7 +41,6 @@ #include #include - #include #include @@ -50,7 +48,7 @@ class SMESHDS_Document; class SMESH_Algo; class SMESH_Mesh; class TopoDS_Shape; - +class SMESH_subMesh; typedef SMESH_Hypothesis::Hypothesis_Status TAlgoStateErrorName; @@ -79,7 +77,7 @@ public: SHAPE_ONLY_UPWARD = 3 // SHAPE_ONLY | UPWARD }; /*! - * \brief Computes aMesh on aShape + * \brief Computes aMesh on aShape * \param aMesh - the mesh. * \param aShape - the shape. * \param aFlags - ComputeFlags. By default compute the whole mesh and compact at the end. @@ -103,7 +101,7 @@ public: const SMESH_subMesh* GetCurrentSubMesh() const; /*! - * \brief evaluates size of prospective mesh on a shape + * \brief evaluates size of prospective mesh on a shape * \param aMesh - the mesh * \param aShape - the shape * \param aResMap - map for prospective numbers of elements @@ -169,28 +167,6 @@ public: private: - - bool parallelComputeSubMeshes( - SMESH_Mesh & aMesh, - const TopoDS_Shape & aShape, - const ::MeshDimension aDim, - TSetOfInt* aShapesId, - TopTools_IndexedMapOfShape* allowedSubShapes, - SMESH_subMesh::compute_event &computeEvent, - const bool includeSelf, - const bool complexShapeFirst, - const bool aShapeOnly); - - bool sequentialComputeSubMeshes( - 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); int _localId; // unique Id of created objects, within SMESH_Gen entity StudyContextStruct* _studyContext; diff --git a/src/SMESH/SMESH_Mesh.cxx b/src/SMESH/SMESH_Mesh.cxx index 077fd7f44..5ff4c1830 100644 --- a/src/SMESH/SMESH_Mesh.cxx +++ b/src/SMESH/SMESH_Mesh.cxx @@ -80,9 +80,6 @@ #include #endif -#include -namespace fs=boost::filesystem; - // maximum stored group name length in MED file #define MAX_MED_GROUP_NAME_LENGTH 80 @@ -124,9 +121,6 @@ SMESH_Mesh::SMESH_Mesh(int theLocalId, _callUp = NULL; _meshDS->ShapeToMesh( PseudoShape() ); _subMeshHolder = new SubMeshHolder; - // 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); // assure unique persistent ID if ( _document->NbMeshes() > 1 ) @@ -174,11 +168,13 @@ namespace #ifndef WIN32 void deleteMeshDS(SMESHDS_Mesh* meshDS) { + //cout << "deleteMeshDS( " << meshDS << endl; delete meshDS; } #else static void* deleteMeshDS(void* meshDS) { + //cout << "deleteMeshDS( " << meshDS << endl; SMESHDS_Mesh* m = (SMESHDS_Mesh*)meshDS; if(m) { delete m; @@ -239,12 +235,6 @@ SMESH_Mesh::~SMESH_Mesh() int result=pthread_create(&thread, NULL, deleteMeshDS, (void*)_meshDS); #endif } - - if(_pool) - DeletePoolThreads(); -#ifndef _DEBUG_ - fs::remove_all(tmp_folder); -#endif } //================================================================================ @@ -542,7 +532,7 @@ int SMESH_Mesh::MEDToMesh(const char* theFileName, const char* theMeshName) Driver_Mesh::Status status = myReader.Perform(); #ifdef _DEBUG_ SMESH_ComputeErrorPtr er = myReader.GetError(); - if ( er && !er->IsOK() ) MESSAGE(er->myComment); + if ( er && !er->IsOK() ) std::cout << er->myComment << std::endl; #endif // Reading groups (sub-meshes are out of scope of MED import functionality) @@ -1771,6 +1761,7 @@ double SMESH_Mesh::GetComputeProgress() const rate = algo->GetProgressByTic(); computedCost += algoDoneCost + rate * algoNotDoneCost; } + // cout << "rate: "<GetMeshInfo().NbElements() << endl; return computedCost / totalCost; } diff --git a/src/SMESH/SMESH_Mesh.hxx b/src/SMESH/SMESH_Mesh.hxx index 18da4e93f..461e949da 100644 --- a/src/SMESH/SMESH_Mesh.hxx +++ b/src/SMESH/SMESH_Mesh.hxx @@ -48,10 +48,6 @@ #include #include -#include -#include -#include - #ifdef WIN32 #pragma warning(disable:4251) // Warning DLL Interface ... #pragma warning(disable:4290) // Warning Exception ... @@ -131,20 +127,20 @@ class SMESH_EXPORT SMESH_Mesh int UNVToMesh(const char* theFileName); int MEDToMesh(const char* theFileName, const char* theMeshName); - + std::string STLToMesh(const char* theFileName); int CGNSToMesh(const char* theFileName, const int theMeshIndex, std::string& theMeshName); - + SMESH_ComputeErrorPtr GMFToMesh(const char* theFileName, bool theMakeRequiredGroups = true ); SMESH_Hypothesis::Hypothesis_Status AddHypothesis(const TopoDS_Shape & aSubShape, int anHypId, std::string* error=0); - + SMESH_Hypothesis::Hypothesis_Status RemoveHypothesis(const TopoDS_Shape & aSubShape, int anHypId); - + const std::list & GetHypothesisList(const TopoDS_Shape & aSubShape) const; @@ -152,7 +148,7 @@ class SMESH_EXPORT SMESH_Mesh const SMESH_HypoFilter& aFilter, const bool andAncestors, TopoDS_Shape* assignedTo=0) const; - + int GetHypotheses(const TopoDS_Shape & aSubShape, const SMESH_HypoFilter& aFilter, std::list< const SMESHDS_Hypothesis * >& aHypList, @@ -163,7 +159,7 @@ class SMESH_EXPORT SMESH_Mesh const SMESH_HypoFilter& aFilter, const bool andAncestors, TopoDS_Shape* assignedTo=0) const; - + int GetHypotheses(const SMESH_subMesh * aSubMesh, const SMESH_HypoFilter& aFilter, std::list< const SMESHDS_Hypothesis * >& aHypList, @@ -173,25 +169,25 @@ class SMESH_EXPORT SMESH_Mesh SMESH_Hypothesis * GetHypothesis(const int aHypID) const; const std::list & GetLog(); - + void ClearLog(); - + int GetId() const { return _id; } - + bool MeshExists( int meshId ) const; - + SMESH_Mesh* FindMesh( int meshId ) const; SMESHDS_Mesh * GetMeshDS() { return _meshDS; } const SMESHDS_Mesh * GetMeshDS() const { return _meshDS; } - + SMESH_Gen *GetGen() { return _gen; } SMESH_subMesh *GetSubMesh(const TopoDS_Shape & aSubShape); - + SMESH_subMesh *GetSubMeshContaining(const TopoDS_Shape & aSubShape) const; - + SMESH_subMesh *GetSubMeshContaining(const int aShapeID) const; /*! * \brief Return submeshes of groups containing the given subshape @@ -213,7 +209,7 @@ class SMESH_EXPORT SMESH_Mesh * \brief check if a hypothesis allowing notconform mesh is present */ bool IsNotConformAllowed() const; - + bool IsMainShape(const TopoDS_Shape& theShape) const; TopoDS_Shape GetShapeByEntry(const std::string& entry) const; @@ -307,20 +303,20 @@ class SMESH_EXPORT SMESH_Mesh bool withRequiredGroups = true ); double GetComputeProgress() const; - + smIdType NbNodes() const; smIdType Nb0DElements() const; smIdType NbBalls() const; - + smIdType NbEdges(SMDSAbs_ElementOrder order = ORDER_ANY) const; - + smIdType NbFaces(SMDSAbs_ElementOrder order = ORDER_ANY) const; smIdType NbTriangles(SMDSAbs_ElementOrder order = ORDER_ANY) const; smIdType NbQuadrangles(SMDSAbs_ElementOrder order = ORDER_ANY) const; smIdType NbBiQuadQuadrangles() const; smIdType NbBiQuadTriangles() const; smIdType NbPolygons(SMDSAbs_ElementOrder order = ORDER_ANY) const; - + smIdType NbVolumes(SMDSAbs_ElementOrder order = ORDER_ANY) const; smIdType NbTetras(SMDSAbs_ElementOrder order = ORDER_ANY) const; smIdType NbHexas(SMDSAbs_ElementOrder order = ORDER_ANY) const; @@ -331,9 +327,9 @@ class SMESH_EXPORT SMESH_Mesh smIdType NbBiQuadPrisms() const; smIdType NbHexagonalPrisms() const; smIdType NbPolyhedrons() const; - + smIdType NbSubMesh() const; - + size_t NbGroup() const { return _mapGroup.size(); } int NbMeshes() const; // nb meshes in the Study @@ -348,9 +344,9 @@ class SMESH_EXPORT SMESH_Mesh typedef boost::shared_ptr< SMDS_Iterator > GroupIteratorPtr; GroupIteratorPtr GetGroups() const; - + std::list GetGroupIds() const; - + SMESH_Group* GetGroup (const int theGroupID) const; bool RemoveGroup (const int theGroupID); @@ -385,27 +381,7 @@ class SMESH_EXPORT SMESH_Mesh const SMESH_subMesh* smAfter ) const; std::ostream& Dump(std::ostream & save); - - // Parallel computation functions - - void Lock() {_my_lock.lock();}; - void Unlock() {_my_lock.unlock();}; - - int GetNbThreads(){return _NbThreads;}; - void SetNbThreads(int nbThreads){_NbThreads=nbThreads;}; - - void InitPoolThreads(){_pool = new boost::asio::thread_pool(_NbThreads);}; - void DeletePoolThreads(){delete _pool;}; - - void wait(){_pool->join(); DeletePoolThreads(); InitPoolThreads(); } - - bool IsParallel(){return _NbThreads > 0;} - - // Temporary folder used during parallel Computation - boost::filesystem::path tmp_folder; - boost::asio::thread_pool * _pool = nullptr; //thread pool for computation - - + private: void exportMEDCommmon(DriverMED_W_SMESHDS_Mesh& myWriter, @@ -421,7 +397,7 @@ private: void fillAncestorsMap(const TopoDS_Shape& theShape); void getAncestorsSubMeshes(const TopoDS_Shape& theSubShape, std::vector< SMESH_subMesh* >& theSubMeshes) const; - + protected: int _id; // id given by creator (unique within the creator instance) int _groupId; // id generator for group objects @@ -434,12 +410,12 @@ protected: class SubMeshHolder; SubMeshHolder* _subMeshHolder; - + bool _isAutoColor; bool _isModified; //!< modified since last total re-compute, issue 0020693 double _shapeDiagonal; //!< diagonal size of bounding box of shape to mesh - + TopTools_IndexedDataMapOfShapeListOfShape _mapAncestors; mutable std::vector _ancestorSubMeshes; // to speed up GetHypothes[ei]s() @@ -452,12 +428,9 @@ protected: // 2) to forget not loaded mesh data at hyp modification TCallUp* _callUp; - // Mutex for multhitreading write in SMESH_Mesh - boost::mutex _my_lock; - int _NbThreads=0; - protected: SMESH_Mesh(); SMESH_Mesh(const SMESH_Mesh&) {}; }; + #endif diff --git a/src/SMESH/SMESH_MeshLocker.cxx b/src/SMESH/SMESH_MeshLocker.cxx deleted file mode 100644 index d04ce9248..000000000 --- a/src/SMESH/SMESH_MeshLocker.cxx +++ /dev/null @@ -1,46 +0,0 @@ -// 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_MeshLocker.cxx -// Author : Yoann AUDOUIN, EDF -// Module : SMESH -// - -#include "SMESH_MeshLocker.hxx" - -#include "SMESH_Mesh.hxx" - -/* - * When instanced will run the command Lock from a SMESH_Mesh - */ -SMESH_MeshLocker::SMESH_MeshLocker(SMESH_Mesh * aMesh) : _myMesh(aMesh) -{ - _myMesh->Lock(); -} - -/* - * When freed will run the command Unlock from the SMESH_Mesh associated - */ -SMESH_MeshLocker::~SMESH_MeshLocker() -{ - _myMesh->Unlock(); -} diff --git a/src/SMESH/SMESH_MeshLocker.hxx b/src/SMESH/SMESH_MeshLocker.hxx deleted file mode 100644 index e38c31b29..000000000 --- a/src/SMESH/SMESH_MeshLocker.hxx +++ /dev/null @@ -1,44 +0,0 @@ -// 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_Mesh.hxx -// Author : Paul RASCLE, EDF -// Module : SMESH -// -#ifndef _SMESH_MESHLOCKER_HXX_ -#define _SMESH_MESHLOCKER_HXX_ - -class SMESH_Mesh; - -class SMESH_MeshLocker{ -public: - SMESH_MeshLocker(SMESH_Mesh * aMesh); - ~SMESH_MeshLocker(); - -protected: - SMESH_MeshLocker(); - -private: - SMESH_Mesh * _myMesh=nullptr; -}; - -#endif diff --git a/src/SMESH/SMESH_MesherHelper.cxx b/src/SMESH/SMESH_MesherHelper.cxx index f426d73f4..28ef9ae55 100644 --- a/src/SMESH/SMESH_MesherHelper.cxx +++ b/src/SMESH/SMESH_MesherHelper.cxx @@ -28,7 +28,7 @@ #include "SMDS_EdgePosition.hxx" #include "SMDS_FaceOfNodes.hxx" -#include "SMDS_FacePosition.hxx" +#include "SMDS_FacePosition.hxx" #include "SMDS_IteratorOnIterators.hxx" #include "SMDS_VolumeTool.hxx" #include "SMESHDS_Mesh.hxx" @@ -100,7 +100,7 @@ SMESH_MesherHelper::SMESH_MesherHelper(SMESH_Mesh& theMesh) //======================================================================= //function : ~SMESH_MesherHelper -//purpose : +//purpose : //======================================================================= SMESH_MesherHelper::~SMESH_MesherHelper() @@ -425,7 +425,7 @@ bool SMESH_MesherHelper::GetNodeUVneedInFaceNode(const TopoDS_Face& F) const //======================================================================= //function : IsMedium -//purpose : +//purpose : //======================================================================= bool SMESH_MesherHelper::IsMedium(const SMDS_MeshNode* node, @@ -583,7 +583,7 @@ bool SMESH_MesherHelper::toCheckPosOnShape(int shapeID ) const void SMESH_MesherHelper::setPosOnShapeValidity(int shapeID, bool ok ) const { - std::map< int,bool >::iterator sh_ok = + std::map< int,bool >::iterator sh_ok = ((SMESH_MesherHelper*)this)->myNodePosShapesValidity.insert( make_pair( shapeID, ok)).first; if ( !ok ) sh_ok->second = ok; @@ -591,7 +591,7 @@ void SMESH_MesherHelper::setPosOnShapeValidity(int shapeID, bool ok ) const //======================================================================= //function : ToFixNodeParameters -//purpose : Enables fixing node parameters on EDGEs and FACEs in +//purpose : Enables fixing node parameters on EDGEs and FACEs in // GetNodeU(...,check=true), GetNodeUV(...,check=true), CheckNodeUV() and // CheckNodeU() in case if a node lies on a shape set via SetSubShape(). // Default is False @@ -943,7 +943,7 @@ namespace { gp_XY AverageUV(const gp_XY& uv1, const gp_XY& uv2) { return ( uv1 + uv2 ) / 2.; } gp_XY_FunPtr(Added); // define gp_XY_Added pointer to function calling gp_XY::Added(gp_XY) - gp_XY_FunPtr(Subtracted); + gp_XY_FunPtr(Subtracted); } //======================================================================= @@ -967,9 +967,9 @@ gp_XY SMESH_MesherHelper::ApplyIn2D(Handle(Geom_Surface) surface, return fun(uv1,uv2); // move uv2 not far than half-period from uv1 - double u2 = + double u2 = uv2.X()+(isUPeriodic ? ShapeAnalysis::AdjustByPeriod(uv2.X(),uv1.X(),surface->UPeriod()) :0); - double v2 = + double v2 = uv2.Y()+(isVPeriodic ? ShapeAnalysis::AdjustByPeriod(uv2.Y(),uv1.Y(),surface->VPeriod()) :0); // execute operation @@ -1038,8 +1038,8 @@ gp_XY SMESH_MesherHelper::GetMiddleUV(const Handle(Geom_Surface)& surface, //======================================================================= gp_XY SMESH_MesherHelper::GetCenterUV(const gp_XY& uv1, - const gp_XY& uv2, - const gp_XY& uv3, + const gp_XY& uv2, + const gp_XY& uv3, const gp_XY& uv12, const gp_XY& uv23, const gp_XY& uv31, @@ -1370,7 +1370,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1, TBiQuad keyOfMap(n1,n2,n3,n4); std::map::iterator itMapCentralNode; itMapCentralNode = myMapWithCentralNode.find( keyOfMap ); - if ( itMapCentralNode != myMapWithCentralNode.end() ) + if ( itMapCentralNode != myMapWithCentralNode.end() ) { return (*itMapCentralNode).second; } @@ -1385,9 +1385,9 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1, std::map< int, int > faceId2nbNodes; std::map< int, int > ::iterator itMapWithIdFace; - + SMESHDS_Mesh* meshDS = GetMeshDS(); - + // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or // on sub-shapes of the FACE if ( GetMesh()->HasShapeToMesh() ) @@ -1545,7 +1545,7 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1, TBiQuad keyOfMap(n1,n2,n3); std::map::iterator itMapCentralNode; itMapCentralNode = myMapWithCentralNode.find( keyOfMap ); - if ( itMapCentralNode != myMapWithCentralNode.end() ) + if ( itMapCentralNode != myMapWithCentralNode.end() ) { return (*itMapCentralNode).second; } @@ -1560,9 +1560,9 @@ const SMDS_MeshNode* SMESH_MesherHelper::GetCentralNode(const SMDS_MeshNode* n1, std::map< int, int > faceId2nbNodes; std::map< int, int > ::iterator itMapWithIdFace; - + SMESHDS_Mesh* meshDS = GetMeshDS(); - + // check if a face lies on a FACE, i.e. its all corner nodes lie either on the FACE or // on sub-shapes of the FACE if ( GetMesh()->HasShapeToMesh() ) @@ -2004,7 +2004,7 @@ SMDS_MeshEdge* SMESH_MesherHelper::AddEdge(const SMDS_MeshNode* n1, const bool force3d) { SMESHDS_Mesh * meshDS = GetMeshDS(); - + SMDS_MeshEdge* edge = 0; if (myCreateQuadratic) { const SMDS_MeshNode* n12 = GetMediumNode(n1,n2,force3d); @@ -2467,7 +2467,7 @@ SMDS_MeshVolume* SMESH_MesherHelper::AddVolume(const SMDS_MeshNode* n1, const SMDS_MeshNode* n10, const SMDS_MeshNode* n11, const SMDS_MeshNode* n12, - const smIdType id, + const smIdType id, bool /*force3d*/) { SMESHDS_Mesh * meshDS = GetMeshDS(); @@ -3206,7 +3206,7 @@ bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, //======================================================================= //function : IsSubShape -//purpose : +//purpose : //======================================================================= bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMesh ) @@ -3221,7 +3221,7 @@ bool SMESH_MesherHelper::IsSubShape( const TopoDS_Shape& shape, SMESH_Mesh* aMes //======================================================================= //function : IsBlock -//purpose : +//purpose : //======================================================================= bool SMESH_MesherHelper::IsBlock( const TopoDS_Shape& shape ) @@ -3324,7 +3324,7 @@ double SMESH_MesherHelper::GetAngle( const TopoDS_Edge & theE1, if ( ++nbLoops > 10 ) { #ifdef _DEBUG_ - MESSAGE("SMESH_MesherHelper::GetAngle(): Captured in a singularity"); + cout << "SMESH_MesherHelper::GetAngle(): Captured in a sigularity" << endl; #endif return angle; } @@ -3404,7 +3404,7 @@ TopoDS_Vertex SMESH_MesherHelper::IthVertex( const bool is2nd, //================================================================================ /*! - * \brief Return type of shape contained in a group + * \brief Return type of shape contained in a group * \param group - a shape of type TopAbs_COMPOUND * \param avoidCompound - not to return TopAbs_COMPOUND */ @@ -3464,13 +3464,13 @@ SMESH_MesherHelper:: MType SMESH_MesherHelper::IsQuadraticMesh() NbAllEdgsAndFaces = myMesh->NbEdges() + myMesh->NbFaces(); if ( NbAllEdgsAndFaces == 0 ) return SMESH_MesherHelper::LINEAR; - + //Quadratic faces and edges NbQuadFacesAndEdgs = myMesh->NbEdges(ORDER_QUADRATIC) + myMesh->NbFaces(ORDER_QUADRATIC); //Linear faces and edges NbFacesAndEdges = myMesh->NbEdges(ORDER_LINEAR) + myMesh->NbFaces(ORDER_LINEAR); - + if (NbAllEdgsAndFaces == NbQuadFacesAndEdgs) { //Quadratic mesh return SMESH_MesherHelper::QUADRATIC; @@ -4120,7 +4120,7 @@ namespace { // Structures used by FixQuadraticElements() } } else if ( _sides.size() < 4 ) - return thePrevLen; + return thePrevLen; // propagate to adjacent faces till limit step or boundary double len1 = thePrevLen + (theLink->MiddlePnt() - _sides[iL1]->MiddlePnt()).Modulus(); @@ -4210,7 +4210,7 @@ namespace { // Structures used by FixQuadraticElements() void QLink::SetContinuesFaces() const { // x0 x - QLink, [-|] - QFace, v - volume - // v0 | v1 + // v0 | v1 // | Between _faces of link x2 two vertical faces are continues // x1----x2-----x3 and two horizontal faces are continues. We set vertical faces // | to _faces[0] and _faces[1] and horizontal faces to @@ -4317,7 +4317,7 @@ namespace { // Structures used by FixQuadraticElements() } return isStraight; } - + //================================================================================ /*! * \brief Move medium nodes of vertical links of pentahedrons adjacent by side faces @@ -4446,13 +4446,13 @@ namespace { // Structures used by FixQuadraticElements() while ( startLink != linksEnd) // loop on columns { // We suppose we have a rectangular structure like shown here. We have found a - // corner of the rectangle (startCorner) and a boundary link sharing - // |/ |/ | the startCorner (startLink). We are going to loop on rows of the - // --o---o---o structure making several chains at once. One chain (columnChain) - // |\ | /| starts at startLink and continues upward (we look at the structure - // \ | \ | / | from such point that startLink is on the bottom of the structure). - // \| \|/ | While going upward we also fill horizontal chains (rowChains) we - // --o---o---o encounter. + // corner of the rectangle (startCorner) and a boundary link sharing + // |/ |/ | the startCorner (startLink). We are going to loop on rows of the + // --o---o---o structure making several chains at once. One chain (columnChain) + // |\ | /| starts at startLink and continues upward (we look at the structure + // \ | \ | / | from such point that startLink is on the bottom of the structure). + // \| \|/ | While going upward we also fill horizontal chains (rowChains) we + // --o---o---o encounter. // /|\ |\ | // / | \ | \ | startCorner // | \| \|,' @@ -4715,7 +4715,7 @@ namespace { // Structures used by FixQuadraticElements() continue; gp_XYZ edgeDir = SMESH_TNodeXYZ( nOnEdge[0] ) - SMESH_TNodeXYZ( nOnEdge[1] ); gp_XYZ edgeNorm = faceNorm ^ edgeDir; - n = theHelper.GetMediumNode( nOnEdge[0], nOnEdge[1], true ); // find n, not create + n = theHelper.GetMediumNode( nOnEdge[0], nOnEdge[1], true ); // find n, not create gp_XYZ pN0 = SMESH_TNodeXYZ( nOnEdge[0] ); gp_XYZ pMedium = SMESH_TNodeXYZ( n ); // on-edge node location gp_XYZ pFaceN = SMESH_TNodeXYZ( nOnFace ); // on-face node location @@ -5440,7 +5440,7 @@ void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError, { uv[ i ] = GetNodeUV( F, nodes[i], nodes[8], &checkUV ); // as this method is used after mesh generation, UV of nodes is not - // updated according to bending links, so we update + // updated according to bending links, so we update if ( i > 3 && nodes[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) CheckNodeUV( F, nodes[i], uv[ i ], 2*tol, /*force=*/true ); } @@ -5475,7 +5475,7 @@ void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError, { uv[ i ] = GetNodeUV( F, nodes[i], nodes[(i+1)%3], &uvOK ); // as this method is used after mesh generation, UV of nodes is not - // updated according to bending links, so we update + // updated according to bending links, so we update if ( nodes[i]->GetPosition()->GetTypeOfPosition() == SMDS_TOP_FACE ) CheckNodeUV( F, nodes[i], uv[ i ], 2*tol, /*force=*/true ); } @@ -5542,16 +5542,16 @@ void SMESH_MesherHelper::FixQuadraticElements(SMESH_ComputeErrorPtr& compError, pointsOnShapes[ SMESH_Block::ID_Ex11 ] = SMESH_TNodeXYZ( hexNodes[ 13 ] ); pointsOnShapes[ SMESH_Block::ID_E0y1 ] = SMESH_TNodeXYZ( hexNodes[ 12 ] ); pointsOnShapes[ SMESH_Block::ID_E1y1 ] = SMESH_TNodeXYZ( hexNodes[ 14 ] ); - pointsOnShapes[ SMESH_Block::ID_E00z ] = SMESH_TNodeXYZ( hexNodes[ 16 ] ); - pointsOnShapes[ SMESH_Block::ID_E10z ] = SMESH_TNodeXYZ( hexNodes[ 19 ] ); - pointsOnShapes[ SMESH_Block::ID_E01z ] = SMESH_TNodeXYZ( hexNodes[ 17 ] ); + pointsOnShapes[ SMESH_Block::ID_E00z ] = SMESH_TNodeXYZ( hexNodes[ 16 ] ); + pointsOnShapes[ SMESH_Block::ID_E10z ] = SMESH_TNodeXYZ( hexNodes[ 19 ] ); + pointsOnShapes[ SMESH_Block::ID_E01z ] = SMESH_TNodeXYZ( hexNodes[ 17 ] ); pointsOnShapes[ SMESH_Block::ID_E11z ] = SMESH_TNodeXYZ( hexNodes[ 18 ] ); pointsOnShapes[ SMESH_Block::ID_Fxy0 ] = SMESH_TNodeXYZ( hexNodes[ 20 ] ); pointsOnShapes[ SMESH_Block::ID_Fxy1 ] = SMESH_TNodeXYZ( hexNodes[ 25 ] ); - pointsOnShapes[ SMESH_Block::ID_Fx0z ] = SMESH_TNodeXYZ( hexNodes[ 21 ] ); - pointsOnShapes[ SMESH_Block::ID_Fx1z ] = SMESH_TNodeXYZ( hexNodes[ 23 ] ); - pointsOnShapes[ SMESH_Block::ID_F0yz ] = SMESH_TNodeXYZ( hexNodes[ 24 ] ); + pointsOnShapes[ SMESH_Block::ID_Fx0z ] = SMESH_TNodeXYZ( hexNodes[ 21 ] ); + pointsOnShapes[ SMESH_Block::ID_Fx1z ] = SMESH_TNodeXYZ( hexNodes[ 23 ] ); + pointsOnShapes[ SMESH_Block::ID_F0yz ] = SMESH_TNodeXYZ( hexNodes[ 24 ] ); pointsOnShapes[ SMESH_Block::ID_F1yz ] = SMESH_TNodeXYZ( hexNodes[ 22 ] ); gp_XYZ nCenterParams(0.5, 0.5, 0.5), nCenterCoords; @@ -5588,6 +5588,8 @@ void SMESH_MesherHelper::WriteShape(const TopoDS_Shape& s) { const char* name = "/tmp/shape.brep"; BRepTools::Write( s, name ); - MESSAGE(name); +#ifdef _DEBUG_ + std::cout << name << std::endl; +#endif } diff --git a/src/SMESH/SMESH_subMesh.cxx b/src/SMESH/SMESH_subMesh.cxx index 76dfb83e1..0b697d7a0 100644 --- a/src/SMESH/SMESH_subMesh.cxx +++ b/src/SMESH/SMESH_subMesh.cxx @@ -37,7 +37,6 @@ #include "SMESH_Mesh.hxx" #include "SMESH_MesherHelper.hxx" #include "SMESH_subMeshEventListener.hxx" -#include "SMESH_MeshLocker.hxx" #include "utilities.h" #include "Basics_Utils.hxx" @@ -63,7 +62,7 @@ using namespace std; #ifdef _DEBUG_ // enable printing algo + shape id + hypo used while meshing -#define PRINT_WHO_COMPUTE_WHAT +//#define PRINT_WHO_COMPUTE_WHAT #endif //============================================================================= @@ -257,7 +256,7 @@ bool SMESH_subMesh::IsMeshComputed() const TopExp_Explorer exp( _subShape, (TopAbs_ShapeEnum) type ); for ( ; exp.More(); exp.Next() ) { - if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( exp.Current() ) ) + if ( SMESHDS_SubMesh * smDS = meshDS->MeshElements( exp.Current() )) { bool computed = (dim > 0) ? smDS->NbElements() : smDS->NbNodes(); if ( computed ) @@ -610,7 +609,7 @@ bool SMESH_subMesh::IsApplicableHypothesis(const SMESH_Hypothesis* theHypothesis * \param [in] event - what happens * \param [in] anHyp - a hypothesis * \return SMESH_Hypothesis::Hypothesis_Status - a treatment result. - * + * * Optional description of a problematic situation (if any) can be retrieved * via GetComputeError(). */ @@ -1034,8 +1033,8 @@ SMESH_Hypothesis::Hypothesis_Status // detect algorithm hiding // - if ( ret == SMESH_Hypothesis::HYP_OK && - ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && algo && + if ( ret == SMESH_Hypothesis::HYP_OK && + ( event == ADD_ALGO || event == ADD_FATHER_ALGO ) && algo && algo->GetName() == anHyp->GetName() ) { // is algo hidden? @@ -1393,7 +1392,6 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event) else if (( event == COMPUTE || event == COMPUTE_SUBMESH ) && !_alwaysComputed ) { - SMESH_MeshLocker myLocker(_father); const TopoDS_Vertex & V = TopoDS::Vertex( _subShape ); gp_Pnt P = BRep_Tool::Pnt(V); if ( SMDS_MeshNode * n = _father->GetMeshDS()->AddNode(P.X(), P.Y(), P.Z()) ) { @@ -1513,10 +1511,9 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event) break; } TopoDS_Shape shape = _subShape; - algo->setSubMeshesToCompute(this); + algo->SubMeshesToCompute().assign( 1, this ); // check submeshes needed - // In parallel there would be no submesh to check - if (_father->HasShapeToMesh() && !_father->IsParallel()) { + if (_father->HasShapeToMesh() ) { bool subComputed = false, subFailed = false; if (!algo->OnlyUnaryInput()) { // --- commented for bos#22320 to compute all sub-shapes at once if possible; @@ -1578,7 +1575,7 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event) _computeError = SMESH_ComputeError::Worst( _computeError, algo->GetComputeError() ); } catch ( ::SMESH_ComputeError& comperr ) { - MESSAGE(" SMESH_ComputeError caught"); + cout << " SMESH_ComputeError caught" << endl; if ( !_computeError ) _computeError = SMESH_ComputeError::New(); *_computeError = comperr; } @@ -1645,9 +1642,8 @@ bool SMESH_subMesh::ComputeStateEngine(compute_event event) #ifdef PRINT_WHO_COMPUTE_WHAT for (subS.ReInit(); subS.More(); subS.Next()) { - SMESH_MeshLocker myLocker(_father); const std::list & hyps = - _algo->GetUsedHypothesis( *_father, _subShape ); + _algo->GetUsedHypothesis( *_father, _subShape ); SMESH_Comment hypStr; if ( !hyps.empty() ) { @@ -2101,7 +2097,7 @@ void SMESH_subMesh::updateDependantsState(const compute_event theEvent) //======================================================================= //function : cleanDependants -//purpose : +//purpose : //======================================================================= void SMESH_subMesh::cleanDependants() @@ -2125,7 +2121,7 @@ void SMESH_subMesh::cleanDependants() //======================================================================= //function : removeSubMeshElementsAndNodes -//purpose : +//purpose : //======================================================================= void SMESH_subMesh::removeSubMeshElementsAndNodes() @@ -2301,7 +2297,7 @@ SMESH_subMesh::OwnListenerData::OwnListenerData( SMESH_subMesh* sm, EventListene * \param listener - the listener to store * \param data - the listener data to store * \param where - the submesh to store the listener and it's data - * + * * It remembers the submesh where it puts the listener in order to delete * them when HYP_OK algo_state is lost * After being set, event listener is notified on each event of where submesh. @@ -2323,7 +2319,7 @@ void SMESH_subMesh::SetEventListener(EventListener* listener, * \brief Sets an event listener and its data to a submesh * \param listener - the listener to store * \param data - the listener data to store - * + * * After being set, event listener is notified on each event of a submesh. */ //================================================================================ @@ -2533,7 +2529,7 @@ void SMESH_subMesh::loadDependentMeshes() * \param subMesh - the submesh where the event occurs * \param data - listener data stored in the subMesh * \param hyp - hypothesis, if eventType is algo_event - * + * * The base implementation translates CLEAN event to the subMesh * stored in listener data. Also it sends SUBMESH_COMPUTED event in case of * successful COMPUTE event. diff --git a/src/SMESH/SMESH_subMesh.hxx b/src/SMESH/SMESH_subMesh.hxx index 0f925570a..fbfd222c2 100644 --- a/src/SMESH/SMESH_subMesh.hxx +++ b/src/SMESH/SMESH_subMesh.hxx @@ -69,7 +69,7 @@ class SMESH_EXPORT SMESH_subMesh int GetId() const; // == meshDS->ShapeToIndex( aSubShape ) SMESH_Mesh* GetFather() { return _father; } - + SMESHDS_SubMesh * GetSubMeshDS(); const SMESHDS_SubMesh * GetSubMeshDS() const; @@ -79,7 +79,6 @@ class SMESH_EXPORT SMESH_subMesh SMESH_subMesh *GetFirstToCompute(); SMESH_Algo* GetAlgo() const; - SMESH_Algo* CopyAlgo() const; const std::map < int, SMESH_subMesh * >& DependsOn(); bool DependsOn( const SMESH_subMesh* other ) const; @@ -124,7 +123,7 @@ class SMESH_EXPORT SMESH_subMesh }; // ================================================================== - // Members to track non hierarchical dependencies between sub-meshes + // Members to track non hierarchical dependencies between sub-meshes // ================================================================== /*! @@ -132,7 +131,7 @@ class SMESH_EXPORT SMESH_subMesh * \param listener - the listener to store * \param data - the listener data to store * \param where - the submesh to store the listener and it's data - * + * * The method remembers the submesh \awhere it puts the listener in order to delete * it when HYP_OK algo_state is lost * After being set, event listener is notified on each event of \awhere submesh. @@ -186,7 +185,7 @@ protected: * \brief Sets an event listener and its data to a submesh * \param listener - the listener to store * \param data - the listener data to store - * + * * After being set, event listener is notified on each event of a submesh. */ void setEventListener(EventListener* listener, EventListenerData* data); @@ -246,7 +245,7 @@ public: bool IsApplicableHypothesis(const SMESH_Hypothesis* theHypothesis) const; // return true if theHypothesis can be used to mesh me: // its shape type is checked - + SMESH_Hypothesis::Hypothesis_Status CheckConcurrentHypothesis (SMESH_Hypothesis* theHypothesis); // check if there are several applicable hypothesis on fathers @@ -278,7 +277,7 @@ public: int GetComputeCost() const; // how costly is to compute this sub-mesh - + /*! * \brief Find common submeshes (based on shared subshapes with other * \param theOther submesh to check @@ -320,7 +319,7 @@ protected: /*! * \brief Return a hypothesis attached to theShape. - * + * * If theHyp is provided, similar but not same hypotheses * is returned; else an applicable ones having theHypType * is returned @@ -328,7 +327,7 @@ protected: const SMESH_Hypothesis* getSimilarAttached(const TopoDS_Shape& theShape, const SMESH_Hypothesis * theHyp, const int theHypType = 0); - // + // int computeCost() const; protected: diff --git a/src/SMESHDS/SMESHDS_Mesh.cxx b/src/SMESHDS/SMESHDS_Mesh.cxx index 7d241698f..563e2de98 100644 --- a/src/SMESHDS/SMESHDS_Mesh.cxx +++ b/src/SMESHDS/SMESHDS_Mesh.cxx @@ -99,7 +99,7 @@ int SMESHDS_Mesh::GetPersistentId() const //======================================================================= //function : ShapeToMesh -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::ShapeToMesh(const TopoDS_Shape & S) { @@ -141,7 +141,7 @@ void SMESHDS_Mesh::ShapeToMesh(const TopoDS_Shape & S) //======================================================================= //function : AddHypothesis -//purpose : +//purpose : //======================================================================= bool SMESHDS_Mesh::AddHypothesis(const TopoDS_Shape & SS, @@ -165,7 +165,7 @@ bool SMESHDS_Mesh::AddHypothesis(const TopoDS_Shape & SS, //======================================================================= //function : RemoveHypothesis -//purpose : +//purpose : //======================================================================= bool SMESHDS_Mesh::RemoveHypothesis(const TopoDS_Shape & S, @@ -186,7 +186,7 @@ bool SMESHDS_Mesh::RemoveHypothesis(const TopoDS_Shape & S, //======================================================================= //function : AddNode -//purpose : +//purpose : //======================================================================= SMDS_MeshNode* SMESHDS_Mesh::AddNode(double x, double y, double z) { @@ -204,7 +204,7 @@ SMDS_MeshNode* SMESHDS_Mesh::AddNodeWithID(double x, double y, double z, smIdTyp //======================================================================= //function : MoveNode -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::MoveNode(const SMDS_MeshNode *n, double x, double y, double z) @@ -235,7 +235,7 @@ bool SMESHDS_Mesh::ChangeElementNodes(const SMDS_MeshElement * elem, //======================================================================= //function : ChangePolygonNodes -//purpose : +//purpose : //======================================================================= bool SMESHDS_Mesh::ChangePolygonNodes (const SMDS_MeshElement * elem, std::vector& nodes) @@ -309,7 +309,7 @@ SMDS_Mesh0DElement* SMESHDS_Mesh::Add0DElement(const SMDS_MeshNode * node) //======================================================================= //function :AddBallWithID -//purpose : +//purpose : //======================================================================= SMDS_BallElement* SMESHDS_Mesh::AddBallWithID(smIdType node, double diameter, smIdType ID) @@ -338,7 +338,7 @@ SMDS_BallElement* SMESHDS_Mesh::AddBall (const SMDS_MeshNode * node, //======================================================================= //function :AddEdgeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(smIdType n1, smIdType n2, smIdType ID) @@ -349,7 +349,7 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(smIdType n1, smIdType n2, smIdType ID } SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, + const SMDS_MeshNode * n2, smIdType ID) { return AddEdgeWithID(n1->GetID(), @@ -361,15 +361,15 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdge(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2) { SMDS_MeshEdge* anElem = SMDS_Mesh::AddEdge(n1,n2); - if(anElem) myScript->AddEdge(anElem->GetID(), - n1->GetID(), + if(anElem) myScript->AddEdge(anElem->GetID(), + n1->GetID(), n2->GetID()); return anElem; } //======================================================================= //function :AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3, smIdType ID) { @@ -380,7 +380,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3 SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, - const SMDS_MeshNode * n3, + const SMDS_MeshNode * n3, smIdType ID) { return AddFaceWithID(n1->GetID(), @@ -394,8 +394,8 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace( const SMDS_MeshNode * n1, const SMDS_MeshNode * n3) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1, n2, n3); - if(anElem) myScript->AddFace(anElem->GetID(), - n1->GetID(), + if(anElem) myScript->AddFace(anElem->GetID(), + n1->GetID(), n2->GetID(), n3->GetID()); return anElem; @@ -403,7 +403,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace( const SMDS_MeshNode * n1, //======================================================================= //function :AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType ID) { @@ -415,7 +415,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3 SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n4, smIdType ID) { return AddFaceWithID(n1->GetID(), @@ -431,9 +431,9 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1, n2, n3, n4); - if(anElem) myScript->AddFace(anElem->GetID(), - n1->GetID(), - n2->GetID(), + if(anElem) myScript->AddFace(anElem->GetID(), + n1->GetID(), + n2->GetID(), n3->GetID(), n4->GetID()); return anElem; @@ -441,7 +441,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function :AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType ID) { @@ -453,11 +453,11 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdTyp SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, - const SMDS_MeshNode * n4, + const SMDS_MeshNode * n4, smIdType ID) { - return AddVolumeWithID(n1->GetID(), - n2->GetID(), + return AddVolumeWithID(n1->GetID(), + n2->GetID(), n3->GetID(), n4->GetID(), ID); @@ -469,9 +469,9 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4); - if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), + if(anElem) myScript->AddVolume(anElem->GetID(), + n1->GetID(), + n2->GetID(), n3->GetID(), n4->GetID()); return anElem; @@ -479,7 +479,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function :AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n5, smIdType ID) { @@ -492,13 +492,13 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n5, smIdType ID) { - return AddVolumeWithID(n1->GetID(), - n2->GetID(), + return AddVolumeWithID(n1->GetID(), + n2->GetID(), n3->GetID(), - n4->GetID(), + n4->GetID(), n5->GetID(), ID); } @@ -510,18 +510,18 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, const SMDS_MeshNode * n5) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5); - if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), + if(anElem) myScript->AddVolume(anElem->GetID(), + n1->GetID(), + n2->GetID(), n3->GetID(), - n4->GetID(), + n4->GetID(), n5->GetID()); return anElem; } //======================================================================= //function :AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n5, smIdType n6, smIdType ID) { @@ -535,14 +535,14 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n6, smIdType ID) { - return AddVolumeWithID(n1->GetID(), - n2->GetID(), + return AddVolumeWithID(n1->GetID(), + n2->GetID(), n3->GetID(), - n4->GetID(), - n5->GetID(), + n4->GetID(), + n5->GetID(), n6->GetID(), ID); } @@ -555,19 +555,19 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, const SMDS_MeshNode * n6) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5, n6); - if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), + if(anElem) myScript->AddVolume(anElem->GetID(), + n1->GetID(), + n2->GetID(), n3->GetID(), - n4->GetID(), - n5->GetID(), + n4->GetID(), + n5->GetID(), n6->GetID()); return anElem; } //======================================================================= //function :AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n5, smIdType n6, smIdType n7, smIdType n8, smIdType ID) { @@ -583,16 +583,16 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n5, const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n8, smIdType ID) { - return AddVolumeWithID(n1->GetID(), - n2->GetID(), + return AddVolumeWithID(n1->GetID(), + n2->GetID(), n3->GetID(), - n4->GetID(), - n5->GetID(), - n6->GetID(), - n7->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + n7->GetID(), n8->GetID(), ID); } @@ -607,14 +607,14 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, const SMDS_MeshNode * n8) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5, n6, n7, n8); - if(anElem) myScript->AddVolume(anElem->GetID(), - n1->GetID(), - n2->GetID(), + if(anElem) myScript->AddVolume(anElem->GetID(), + n1->GetID(), + n2->GetID(), n3->GetID(), - n4->GetID(), - n5->GetID(), - n6->GetID(), - n7->GetID(), + n4->GetID(), + n5->GetID(), + n6->GetID(), + n7->GetID(), n8->GetID()); return anElem; } @@ -641,14 +641,14 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n5, const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - const SMDS_MeshNode * n9, - const SMDS_MeshNode * n10, - const SMDS_MeshNode * n11, - const SMDS_MeshNode * n12, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, + const SMDS_MeshNode * n12, smIdType ID) { - return AddVolumeWithID(n1->GetID(), + return AddVolumeWithID(n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), @@ -670,14 +670,14 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, const SMDS_MeshNode * n5, const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, - const SMDS_MeshNode * n9, - const SMDS_MeshNode * n10, - const SMDS_MeshNode * n11, + const SMDS_MeshNode * n8, + const SMDS_MeshNode * n9, + const SMDS_MeshNode * n10, + const SMDS_MeshNode * n11, const SMDS_MeshNode * n12) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1, n2, n3, n4, n5, n6, n7, n8, n9, n10, n11, n12); - if(anElem) myScript->AddVolume(anElem->GetID(), + if(anElem) myScript->AddVolume(anElem->GetID(), n1->GetID(), n2->GetID(), n3->GetID(), @@ -696,7 +696,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddPolygonalFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddPolygonalFaceWithID (const std::vector& nodes_ids, const smIdType ID) @@ -742,7 +742,7 @@ SMESHDS_Mesh::AddPolygonalFace (const std::vector& nodes) //======================================================================= //function : AddQuadPolygonalFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddQuadPolygonalFaceWithID (const std::vector& nodes_ids, const smIdType ID) @@ -788,7 +788,7 @@ SMESHDS_Mesh::AddQuadPolygonalFace (const std::vector& nod //======================================================================= //function : AddPolyhedralVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolumeWithID (const std::vector& nodes_ids, const std::vector& quantities, @@ -836,7 +836,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddPolyhedralVolume //======================================================================= //function : removeFromContainers -//purpose : +//purpose : //======================================================================= static void removeFromContainers (SMESHDS_Mesh* /*theMesh*/, @@ -905,8 +905,8 @@ void SMESHDS_Mesh::RemoveNode(const SMDS_MeshNode * n) } if ( SMESHDS_SubMesh * sm = MeshElements( n->getshapeId() )) sm->RemoveNode( n ); - - + + std::vector removedElems; std::vector removedNodes; @@ -918,7 +918,7 @@ void SMESHDS_Mesh::RemoveNode(const SMDS_MeshNode * n) //======================================================================= //function : RemoveFreeNode -//purpose : +//purpose : //======================================================================= bool SMESHDS_Mesh::RemoveFreeNode(const SMDS_MeshNode * n, SMESHDS_SubMesh * subMesh, @@ -971,20 +971,20 @@ void SMESHDS_Mesh::RemoveElement(const SMDS_MeshElement * elt) RemoveFreeElement( elt, subMesh, true ); return; } - + myScript->RemoveElement(elt->GetID()); std::vector removedElems; std::vector removedNodes; SMDS_Mesh::RemoveElement(elt, removedElems, removedNodes ); - + removeFromContainers( this, myGroups, removedElems ); } //======================================================================= //function : RemoveFreeElement -//purpose : +//purpose : //======================================================================== void SMESHDS_Mesh::RemoveFreeElement(const SMDS_MeshElement * elt, SMESHDS_SubMesh * subMesh, @@ -1151,7 +1151,7 @@ void SMESHDS_Mesh::SetNodeOnVertex(const SMDS_MeshNode * aNode, //======================================================================= //function : UnSetNodeOnShape -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::UnSetNodeOnShape(const SMDS_MeshNode* aNode) { @@ -1173,7 +1173,7 @@ void SMESHDS_Mesh::SetMeshElementOnShape(const SMDS_MeshElement * anElement, //======================================================================= //function : UnSetMeshElementOnShape -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::UnSetMeshElementOnShape(const SMDS_MeshElement * elem, const TopoDS_Shape & S) @@ -1184,7 +1184,7 @@ void SMESHDS_Mesh::UnSetMeshElementOnShape(const SMDS_MeshElement * elem, //======================================================================= //function : ShapeToMesh -//purpose : +//purpose : //======================================================================= TopoDS_Shape SMESHDS_Mesh::ShapeToMesh() const { @@ -1229,7 +1229,7 @@ SMESHDS_SubMesh * SMESHDS_Mesh::MeshElements(const int Index) const //======================================================================= //function : SubMeshIndices -//purpose : +//purpose : //======================================================================= std::list SMESHDS_Mesh::SubMeshIndices() const { @@ -1243,7 +1243,7 @@ std::list SMESHDS_Mesh::SubMeshIndices() const //======================================================================= //function : SubMeshes -//purpose : +//purpose : //======================================================================= SMESHDS_SubMeshIteratorPtr SMESHDS_Mesh::SubMeshes() const @@ -1253,7 +1253,7 @@ SMESHDS_SubMeshIteratorPtr SMESHDS_Mesh::SubMeshes() const //======================================================================= //function : GetHypothesis -//purpose : +//purpose : //======================================================================= const std::list& @@ -1283,7 +1283,7 @@ bool SMESHDS_Mesh::IsUsedHypothesis(const SMESHDS_Hypothesis * H) const //======================================================================= //function : GetScript -//purpose : +//purpose : //======================================================================= SMESHDS_Script* SMESHDS_Mesh::GetScript() { @@ -1292,7 +1292,7 @@ SMESHDS_Script* SMESHDS_Mesh::GetScript() //======================================================================= //function : ClearScript -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::ClearScript() { @@ -1301,7 +1301,7 @@ void SMESHDS_Mesh::ClearScript() //======================================================================= //function : HasMeshElements -//purpose : +//purpose : //======================================================================= bool SMESHDS_Mesh::HasMeshElements(const TopoDS_Shape & S) const { @@ -1311,7 +1311,7 @@ bool SMESHDS_Mesh::HasMeshElements(const TopoDS_Shape & S) const //======================================================================= //function : HasHypothesis -//purpose : +//purpose : //======================================================================= bool SMESHDS_Mesh::HasHypothesis(const TopoDS_Shape & S) { @@ -1319,8 +1319,8 @@ bool SMESHDS_Mesh::HasHypothesis(const TopoDS_Shape & S) } //======================================================================= -//function : NewSubMesh -//purpose : +//function : NewSubMesh +//purpose : //======================================================================= SMESHDS_SubMesh * SMESHDS_Mesh::NewSubMesh(int Index) { @@ -1335,7 +1335,7 @@ SMESHDS_SubMesh * SMESHDS_Mesh::NewSubMesh(int Index) //======================================================================= //function : AddCompoundSubmesh -//purpose : +//purpose : //======================================================================= int SMESHDS_Mesh::AddCompoundSubmesh(const TopoDS_Shape& S, @@ -1370,7 +1370,7 @@ int SMESHDS_Mesh::AddCompoundSubmesh(const TopoDS_Shape& S, //======================================================================= //function : IndexToShape -//purpose : +//purpose : //======================================================================= const TopoDS_Shape& SMESHDS_Mesh::IndexToShape(int ShapeIndex) const { @@ -1399,7 +1399,7 @@ int SMESHDS_Mesh::MaxSubMeshIndex() const //======================================================================= //function : ShapeToIndex -//purpose : +//purpose : //======================================================================= int SMESHDS_Mesh::ShapeToIndex(const TopoDS_Shape & S) const { @@ -1409,7 +1409,7 @@ int SMESHDS_Mesh::ShapeToIndex(const TopoDS_Shape & S) const //======================================================================= //function : SetNodeOnVolume -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::SetNodeInVolume(const SMDS_MeshNode* aNode, int Index) { @@ -1457,7 +1457,7 @@ void SMESHDS_Mesh::SetNodeOnVertex(const SMDS_MeshNode* aNode, int Index) //======================================================================= //function : SetMeshElementOnShape -//purpose : +//purpose : //======================================================================= void SMESHDS_Mesh::SetMeshElementOnShape(const SMDS_MeshElement* anElement, int Index) @@ -1467,7 +1467,7 @@ void SMESHDS_Mesh::SetMeshElementOnShape(const SMDS_MeshElement* anElement, //======================================================================= //function : ~SMESHDS_Mesh -//purpose : +//purpose : //======================================================================= SMESHDS_Mesh::~SMESHDS_Mesh() { @@ -1488,9 +1488,9 @@ SMESHDS_Mesh::~SMESHDS_Mesh() //======================================================================= //function : AddEdgeWithID -//purpose : +//purpose : //======================================================================= -SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(smIdType n1, smIdType n2, smIdType n12, smIdType ID) +SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(smIdType n1, smIdType n2, smIdType n12, smIdType ID) { SMDS_MeshEdge* anElem = SMDS_Mesh::AddEdgeWithID(n1,n2,n12,ID); if(anElem) myScript->AddEdge(ID,n1,n2,n12); @@ -1499,15 +1499,15 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(smIdType n1, smIdType n2, smIdType n1 //======================================================================= //function : AddEdge -//purpose : +//purpose : //======================================================================= SMDS_MeshEdge* SMESHDS_Mesh::AddEdge(const SMDS_MeshNode* n1, const SMDS_MeshNode* n2, const SMDS_MeshNode* n12) { SMDS_MeshEdge* anElem = SMDS_Mesh::AddEdge(n1,n2,n12); - if(anElem) myScript->AddEdge(anElem->GetID(), - n1->GetID(), + if(anElem) myScript->AddEdge(anElem->GetID(), + n1->GetID(), n2->GetID(), n12->GetID()); return anElem; @@ -1515,11 +1515,11 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdge(const SMDS_MeshNode* n1, //======================================================================= //function : AddEdgeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, - const SMDS_MeshNode * n12, + const SMDS_MeshNode * n2, + const SMDS_MeshNode * n12, smIdType ID) { return AddEdgeWithID(n1->GetID(), @@ -1531,7 +1531,7 @@ SMDS_MeshEdge* SMESHDS_Mesh::AddEdgeWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1541,7 +1541,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n31) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n12,n23,n31); - if(anElem) myScript->AddFace(anElem->GetID(), + if(anElem) myScript->AddFace(anElem->GetID(), n1->GetID(), n2->GetID(), n3->GetID(), n12->GetID(), n23->GetID(), n31->GetID()); return anElem; @@ -1549,7 +1549,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n12,smIdType n23,smIdType n31, smIdType ID) @@ -1561,14 +1561,14 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3 //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, smIdType ID) { return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), @@ -1578,7 +1578,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1589,7 +1589,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * nCenter) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n12,n23,n31,nCenter); - if(anElem) myScript->AddFace(anElem->GetID(), + if(anElem) myScript->AddFace(anElem->GetID(), n1->GetID(), n2->GetID(), n3->GetID(), n12->GetID(), n23->GetID(), n31->GetID(), nCenter->GetID()); @@ -1598,7 +1598,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n12,smIdType n23,smIdType n31, smIdType nCenter, smIdType ID) @@ -1610,15 +1610,15 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3 //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, - const SMDS_MeshNode * nCenter, + const SMDS_MeshNode * n31, + const SMDS_MeshNode * nCenter, smIdType ID) { return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), @@ -1629,7 +1629,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1641,7 +1641,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n41) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n4,n12,n23,n34,n41); - if(anElem) myScript->AddFace(anElem->GetID(), + if(anElem) myScript->AddFace(anElem->GetID(), n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID()); return anElem; @@ -1649,7 +1649,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n12,smIdType n23,smIdType n34,smIdType n41, smIdType ID) @@ -1661,7 +1661,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3 //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1669,8 +1669,8 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, smIdType ID) { return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), @@ -1681,7 +1681,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddFace -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1690,11 +1690,11 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * nCenter) { SMDS_MeshFace *anElem = SMDS_Mesh::AddFace(n1,n2,n3,n4,n12,n23,n34,n41,nCenter); - if(anElem) myScript->AddFace(anElem->GetID(), + if(anElem) myScript->AddFace(anElem->GetID(), n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), n12->GetID(), n23->GetID(), n34->GetID(), n41->GetID(), nCenter->GetID()); @@ -1703,7 +1703,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFace(const SMDS_MeshNode * n1, //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n12,smIdType n23,smIdType n34,smIdType n41, @@ -1716,7 +1716,7 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(smIdType n1, smIdType n2, smIdType n3 //======================================================================= //function : AddFaceWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, @@ -1724,9 +1724,9 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, - const SMDS_MeshNode * nCenter, + const SMDS_MeshNode * n34, + const SMDS_MeshNode * n41, + const SMDS_MeshNode * nCenter, smIdType ID) { return AddFaceWithID(n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), @@ -1737,21 +1737,21 @@ SMDS_MeshFace* SMESHDS_Mesh::AddFaceWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, + const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, + const SMDS_MeshNode * n14, const SMDS_MeshNode * n24, const SMDS_MeshNode * n34) { SMDS_MeshVolume *anElem = SMDS_Mesh::AddVolume(n1,n2,n3,n4,n12,n23,n31,n14,n24,n34); - if(anElem) myScript->AddVolume(anElem->GetID(), + if(anElem) myScript->AddVolume(anElem->GetID(), n1->GetID(), n2->GetID(), n3->GetID(), n4->GetID(), n12->GetID(), n23->GetID(), n31->GetID(), n14->GetID(), n24->GetID(), n34->GetID()); @@ -1760,7 +1760,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n12,smIdType n23,smIdType n31, @@ -1771,7 +1771,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdTyp if(anElem) myScript->AddVolume(ID,n1,n2,n3,n4,n12,n23,n31,n14,n24,n34); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order tetrahedron of 10 nodes @@ -1783,7 +1783,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n31, - const SMDS_MeshNode * n14, + const SMDS_MeshNode * n14, const SMDS_MeshNode * n24, const SMDS_MeshNode * n34, smIdType ID) @@ -1796,18 +1796,18 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolume -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, + const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n5, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, const SMDS_MeshNode * n41, - const SMDS_MeshNode * n15, + const SMDS_MeshNode * n15, const SMDS_MeshNode * n25, const SMDS_MeshNode * n35, const SMDS_MeshNode * n45) @@ -1824,7 +1824,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n5, smIdType n12,smIdType n23,smIdType n34,smIdType n41, @@ -1837,7 +1837,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdTyp n15,n25,n35,n45); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order pyramid of 13 nodes @@ -1846,12 +1846,12 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, + const SMDS_MeshNode * n5, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, const SMDS_MeshNode * n41, - const SMDS_MeshNode * n15, + const SMDS_MeshNode * n15, const SMDS_MeshNode * n25, const SMDS_MeshNode * n35, const SMDS_MeshNode * n45, @@ -1870,17 +1870,17 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, //purpose : 2nd order pentahedron (prism) with 15 nodes //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, + const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, const SMDS_MeshNode * n45, const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, + const SMDS_MeshNode * n64, const SMDS_MeshNode * n14, const SMDS_MeshNode * n25, const SMDS_MeshNode * n36) @@ -2000,7 +2000,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdTyp n45,n56,n64,n14,n25,n36, n1245, n2356, n1346); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order Pentahedron with 18 nodes @@ -2009,14 +2009,14 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, - const SMDS_MeshNode * n31, + const SMDS_MeshNode * n31, const SMDS_MeshNode * n45, const SMDS_MeshNode * n56, - const SMDS_MeshNode * n64, + const SMDS_MeshNode * n64, const SMDS_MeshNode * n14, const SMDS_MeshNode * n25, const SMDS_MeshNode * n36, @@ -2039,21 +2039,21 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, //purpose : add quadratic hexahedron //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, + const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n56, const SMDS_MeshNode * n67, const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, + const SMDS_MeshNode * n85, const SMDS_MeshNode * n15, const SMDS_MeshNode * n26, const SMDS_MeshNode * n37, @@ -2075,7 +2075,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, //======================================================================= //function : AddVolumeWithID -//purpose : +//purpose : //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdType n3, smIdType n4, smIdType n5, smIdType n6, smIdType n7, smIdType n8, @@ -2091,7 +2091,7 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(smIdType n1, smIdType n2, smIdTyp n56,n67,n78,n85,n15,n26,n37,n48); return anElem; } - + //======================================================================= //function : AddVolumeWithID //purpose : 2d order Hexahedrons with 20 nodes @@ -2100,18 +2100,18 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n56, const SMDS_MeshNode * n67, const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, + const SMDS_MeshNode * n85, const SMDS_MeshNode * n15, const SMDS_MeshNode * n26, const SMDS_MeshNode * n37, @@ -2132,25 +2132,25 @@ SMDS_MeshVolume* SMESHDS_Mesh::AddVolumeWithID(const SMDS_MeshNode * n1, //======================================================================= SMDS_MeshVolume* SMESHDS_Mesh::AddVolume(const SMDS_MeshNode * n1, - const SMDS_MeshNode * n2, + const SMDS_MeshNode * n2, const SMDS_MeshNode * n3, const SMDS_MeshNode * n4, - const SMDS_MeshNode * n5, - const SMDS_MeshNode * n6, + const SMDS_MeshNode * n5, + const SMDS_MeshNode * n6, const SMDS_MeshNode * n7, - const SMDS_MeshNode * n8, + const SMDS_MeshNode * n8, const SMDS_MeshNode * n12, const SMDS_MeshNode * n23, const SMDS_MeshNode * n34, - const SMDS_MeshNode * n41, + const SMDS_MeshNode * n41, const SMDS_MeshNode * n56, const SMDS_MeshNode * n67, const SMDS_MeshNode * n78, - const SMDS_MeshNode * n85, + const SMDS_MeshNode * n85, const SMDS_MeshNode * n15, const SMDS_MeshNode * n26, const SMDS_MeshNode * n37, - const SMDS_MeshNode * n48, + const SMDS_MeshNode * n48, const SMDS_MeshNode * n1234, const SMDS_MeshNode * n1256, const SMDS_MeshNode * n2367, diff --git a/src/SMESH_I/SMESH_2smeshpy.cxx b/src/SMESH_I/SMESH_2smeshpy.cxx index 4ac51ac99..03a600094 100644 --- a/src/SMESH_I/SMESH_2smeshpy.cxx +++ b/src/SMESH_I/SMESH_2smeshpy.cxx @@ -2212,8 +2212,7 @@ bool _pyMesh::NeedMeshAccess( const Handle(_pyCommand)& theCommand ) "GetElemNode","IsMediumNode","IsMediumNodeOfAnyElem","ElemNbEdges","ElemNbFaces", "GetElemFaceNodes", "GetFaceNormal", "FindElementByNodes", "IsPoly","IsQuadratic","BaryCenter","GetHypothesisList", "SetAutoColor", "GetAutoColor", - "Clear", "ConvertToStandalone", "GetMeshOrder", "SetMeshOrder", - "SetNbThreads" + "Clear", "ConvertToStandalone", "GetMeshOrder", "SetMeshOrder" ,"" }; // <- mark of end sameMethods.Insert( names ); } diff --git a/src/SMESH_I/SMESH_Gen_i.cxx b/src/SMESH_I/SMESH_Gen_i.cxx index 8f57c6c1b..263454015 100644 --- a/src/SMESH_I/SMESH_Gen_i.cxx +++ b/src/SMESH_I/SMESH_Gen_i.cxx @@ -6645,6 +6645,8 @@ CORBA::Boolean SMESH_Gen_i::IsApplicable ( const char* theAlgoType, SMESH_CATCH( SMESH::doNothing ); - MESSAGE("SMESH_Gen_i::IsApplicable(): exception in " << ( theAlgoType ? theAlgoType : "")); +#ifdef _DEBUG_ + cout << "SMESH_Gen_i::IsApplicable(): exception in " << ( theAlgoType ? theAlgoType : "") << endl; +#endif return true; } diff --git a/src/SMESH_I/SMESH_Mesh_i.cxx b/src/SMESH_I/SMESH_Mesh_i.cxx index a7abda6db..b307c7bbb 100644 --- a/src/SMESH_I/SMESH_Mesh_i.cxx +++ b/src/SMESH_I/SMESH_Mesh_i.cxx @@ -2506,7 +2506,7 @@ void SMESH_Mesh_i::CheckGeomModif( bool theIsBreakLink ) } old2newShapeMap.Bind( group->GetShape(), groupsData.back()._shape ); } - + } } // store assigned hypotheses @@ -6170,8 +6170,8 @@ SMESH::SMESH_Mesh_ptr SMESH_Mesh_i::GetMesh() /*! * \brief Return false if GetMeshInfo() return incorrect information that may * happen if mesh data is not yet fully loaded from the file of study. - * - * + * + * */ //================================================================================ @@ -7037,16 +7037,6 @@ TListOfListOfInt SMESH_Mesh_i::findConcurrentSubMeshes() return res; } -//============================================================================= -/*! - * \brief Set the number of threads for a parallel computation - */ -//============================================================================= -void SMESH_Mesh_i::SetNbThreads(int nbThreads){ - _impl->SetNbThreads(nbThreads); -} - - //============================================================================= /*! * \brief Convert submesh ids into submesh interfaces @@ -7239,7 +7229,7 @@ smIdType SMESH_MeshPartDS::MinNodeID() const { if ( _meshDS ) return _meshDS->MinNodeID(); return NbNodes() == 0 ? 0 : (*_elements[ SMDSAbs_Node ].begin())->GetID(); -} +} // ------------------------------------------------------------------------------------- smIdType SMESH_MeshPartDS::MaxElementID() const { diff --git a/src/SMESH_I/SMESH_Mesh_i.hxx b/src/SMESH_I/SMESH_Mesh_i.hxx index 444c7b791..8a50d1226 100644 --- a/src/SMESH_I/SMESH_Mesh_i.hxx +++ b/src/SMESH_I/SMESH_Mesh_i.hxx @@ -226,7 +226,7 @@ public: const char* file, CORBA::Boolean withRequiredGroups); - + template void ExportPartToMEDCommon(SPECLS& speCls, SMESH::SMESH_IDSource_ptr meshPart, @@ -571,7 +571,7 @@ public: * Persistence of geometry tick */ int& MainShapeTick() { return _mainShapeTick; } - + /*! * Sets list of notebook variables used for Mesh operations separated by ":" symbol @@ -673,9 +673,6 @@ private: SMESH::submesh_array_array& theSubMeshOrder, const bool theIsDump); - void SetNbThreads(int nbThreads); - void SetMesherNbThreads(int nbThreads); - /*! * \brief Finds concurrent sub-meshes */ diff --git a/src/SMESH_SWIG/smeshBuilder.py b/src/SMESH_SWIG/smeshBuilder.py index ec65b9fa9..62db88951 100644 --- a/src/SMESH_SWIG/smeshBuilder.py +++ b/src/SMESH_SWIG/smeshBuilder.py @@ -462,21 +462,6 @@ class smeshBuilder( SMESH._objref_SMESH_Gen, object ): obj,name = name,obj return Mesh(self, self.geompyD, obj, name) - def ParallelMesh(self, obj, param, nbThreads, name=0): - """ - 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. - - Returns: - an instance of class :class:`ParallelMesh`. - """ - return ParallelMesh(self, self.geompyD, obj, param, nbThreads, name) - def RemoveMesh( self, mesh ): """ Delete a mesh @@ -1878,6 +1863,7 @@ class Mesh(metaclass = MeshMeta): geom = self.geom return self.smeshpyD.Evaluate(self.mesh, geom) + def Compute(self, geom=0, discardModifs=False, refresh=False): """ Compute the mesh and return the status of the computation @@ -7501,121 +7487,6 @@ class Mesh(metaclass = MeshMeta): pass # end of Mesh class -def _copy_netgen_param(dim, local_param, global_param): - if dim==1: - #TODO: Try to identify why we need to substract 1 - local_param.NumberOfSegments(int(global_param.GetNbSegPerEdge())-1) - elif dim==2: - local_param.SetMaxSize(global_param.GetMaxSize()) - local_param.SetMinSize(global_param.GetMinSize()) - local_param.SetOptimize(global_param.GetOptimize()) - local_param.SetFineness(global_param.GetFineness()) - local_param.SetNbSegPerEdge(global_param.GetNbSegPerEdge()) - local_param.SetNbSegPerRadius(global_param.GetNbSegPerRadius()) - local_param.SetGrowthRate(global_param.GetGrowthRate()*0.9) - local_param.SetChordalError(global_param.GetChordalError()) - local_param.SetChordalErrorEnabled(global_param.GetChordalErrorEnabled()) - local_param.SetUseSurfaceCurvature(global_param.GetUseSurfaceCurvature()) - local_param.SetUseDelauney(global_param.GetUseDelauney()) - local_param.SetQuadAllowed(global_param.GetQuadAllowed()) - local_param.SetWorstElemMeasure(global_param.GetWorstElemMeasure()) - local_param.SetCheckChartBoundary(global_param.GetCheckChartBoundary()) - local_param.SetNbThreads(global_param.GetNbThreads()) - else: - local_param.SetMaxSize(global_param.GetMaxSize()) - local_param.SetMinSize(global_param.GetMinSize()) - local_param.SetOptimize(global_param.GetOptimize()) - local_param.SetCheckOverlapping(global_param.GetCheckOverlapping()) - local_param.SetCheckChartBoundary(global_param.GetCheckChartBoundary()) - local_param.SetFineness(global_param.GetFineness()) - local_param.SetNbSegPerEdge(global_param.GetNbSegPerEdge()) - local_param.SetNbSegPerRadius(global_param.GetNbSegPerRadius()) - local_param.SetGrowthRate(global_param.GetGrowthRate()) - local_param.SetNbThreads(global_param.GetNbThreads()) - -class ParallelMesh(Mesh): - """ - Surcharge on Mesh for parallel computation of a mesh - """ - - def __init__(self, smeshpyD, geompyD, geom, param, nbThreads, name=0): - """ - Create a parallel mesh. - - Parameters: - geom: geometrical object for meshing - param: full mesh parameters - nbThreads: Number of threads for parallelisation. - name: the name for the new mesh. - - Returns: - an instance of class :class:`ParallelMesh`. - """ - - 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") - - if nbThreads < 1: - raise ValueError("Number of threads must be stricly greater than 1") - - # 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) - - 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') - - super(ParallelMesh, self).__init__(smeshpyD, geompyD, geom, name) - - self.mesh.SetNbThreads(nbThreads) - - self.UseExistingSegments() - self.UseExistingFaces() - - algo2d = self.Triangle(geom=all_faces, algo="NETGEN_2D") - param2d = algo2d.Parameters() - - _copy_netgen_param(2, param2d, param) - - 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") - - param3d = algo3d.Parameters() - - _copy_netgen_param(3, param3d, param) - - pass # End of ParallelMesh - - class meshProxy(SMESH._objref_SMESH_Mesh): """ Private class used to compensate change of CORBA API of SMESH_Mesh for backward compatibility diff --git a/src/StdMeshers/StdMeshers_Regular_1D.cxx b/src/StdMeshers/StdMeshers_Regular_1D.cxx index 886f72b63..40e8fbd82 100644 --- a/src/StdMeshers/StdMeshers_Regular_1D.cxx +++ b/src/StdMeshers/StdMeshers_Regular_1D.cxx @@ -716,7 +716,7 @@ void StdMeshers_Regular_1D::redistributeNearVertices (SMESH_Mesh & theM //============================================================================= /*! - * + * */ //============================================================================= bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, @@ -1164,7 +1164,7 @@ bool StdMeshers_Regular_1D::computeInternalParameters(SMESH_Mesh & theMesh, //============================================================================= /*! - * + * */ //============================================================================= @@ -1338,7 +1338,7 @@ bool StdMeshers_Regular_1D::Compute(SMESH_Mesh & theMesh, const TopoDS_Shape & t //============================================================================= /*! - * + * */ //============================================================================= diff --git a/test/SMESH_ParallelCompute.py b/test/SMESH_ParallelCompute.py deleted file mode 100644 index eeddd3f02..000000000 --- a/test/SMESH_ParallelCompute.py +++ /dev/null @@ -1,131 +0,0 @@ -# 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(): - nbox = 2 - boxsize = 100 - run_test(nbox, boxsize) - -main() - diff --git a/test/netgen_runner.py b/test/netgen_runner.py deleted file mode 100644 index be8386fcb..000000000 --- a/test/netgen_runner.py +++ /dev/null @@ -1,129 +0,0 @@ -#!/usr/bin/env python -import sys -import salome - -salome.salome_init() - -from os import path -import tempfile -import subprocess - -import GEOM, SMESH, SALOMEDS - -from salome.geom import geomBuilder -from salome.smesh import smeshBuilder - -import math - -smesh = smeshBuilder.New() -geompy = geomBuilder.New() - -import medcoupling as mc - -def create_param_file(param_file): - """ Create a parameter file for runner """ - param = """1 -34.64 -0.14 -16 -0.15 -1.5 -0 -0 -1 -5 -1 -1 --1 -3 -3 -0.2 -2 -1 -0 -0 -2 -2 -0 - -0 -0 -0""" - with open(param_file, "w") as ffile: - ffile.write(param) - - -def test_netgen3d(): - """ Test netgen3d mesher """ - # Building geometry - box = geompy.MakeBoxDXDYDZ(200, 200, 200) - - geompy.ExtractShapes(box, geompy.ShapeType["FACE"], True) - groupe_1 = geompy.CreateGroup(box, geompy.ShapeType["FACE"]) - geompy.UnionIDs(groupe_1, [3, 13, 23, 27, 31, 33]) - - [_, _, _, _, _, _, groupe_1] = geompy.GetExistingSubObjects(box, False) - - # Creating 2D mesh - netgen_2d_parameters_1 = smesh.CreateHypothesisByAverageLength( - 'NETGEN_Parameters_2D', 'NETGENEngine', 34.641, 0) - mesh_2d = smesh.Mesh(groupe_1, 'Maillage_1') - mesh_2d.AddHypothesis(groupe_1, netgen_2d_parameters_1) - mesh_2d.Triangle(algo=smeshBuilder.NETGEN_1D2D) - is_done = mesh_2d.Compute() - assert is_done - smesh.SetName(mesh_2d, 'Maillage_1') - - with tempfile.TemporaryDirectory() as tmp_dir: - mesh_file = path.join(tmp_dir, "mesh.med") - shape_file = path.join(tmp_dir, "shape.step") - param_file = path.join(tmp_dir, "param.txt") - output_mesh = path.join(tmp_dir, "mesh3D.med") - - print("Running in folder: ", tmp_dir) - create_param_file(param_file) - - mesh_2d.ExportMED(mesh_file, 0, 41, 1, mesh_2d, 1, [], '', -1, 1) - geompy.ExportSTEP(box, shape_file, GEOM.LU_METER) - - runner = path.join("${NETGENPLUGIN_ROOT_DIR}", - "bin", - "salome", - "NETGENPlugin_Runner") - - if sys.platform == 'win32': - runner += ".exe" - - cmd = "{runner} NETGEN3D {mesh_file} {shape_file} "\ - "{param_file} NONE NONE {output_mesh}"\ - .format(runner=runner, - mesh_file=mesh_file, - shape_file=shape_file, - param_file=param_file, - output_mesh=output_mesh) - print(cmd) - subprocess.check_call(cmd, shell=True) - - mesh_read = mc.ReadUMeshFromFile(output_mesh, "MESH", 0) - - nb_tetras = mesh_read.getNumberOfCellsWithType(mc.NORM_TETRA4) - nb_points = mesh_read.getNumberOfNodes() - - mesh_read = mc.ReadUMeshFromFile(output_mesh, "MESH", -1) - nb_triangles = mesh_read.getNumberOfCellsWithType(mc.NORM_TRI3) - - mesh_read = mc.ReadUMeshFromFile(output_mesh, "MESH", -2) - nb_segments = mesh_read.getNumberOfCellsWithType(mc.NORM_SEG2) - - print("Nb Tetras:", nb_tetras) - print("Nb Triangles:", nb_triangles) - print("Nb Segments:", nb_segments) - print("Nb Points:", nb_points) - - assert nb_points > 0 - assert nb_segments > 0 - assert nb_triangles > 0 - assert nb_tetras > 0 - -if __name__ == "__main__": - test_netgen3d() diff --git a/test/tests.set b/test/tests.set index 2c2d901c8..fddb00249 100644 --- a/test/tests.set +++ b/test/tests.set @@ -63,8 +63,6 @@ SET(BAD_TESTS SMESH_test2.py SMESH_test4.py SMESH_create_dual_mesh_adapt.py - netgen_runner.py - SMESH_ParallelCompute.py ) IF(NOT WIN32) LIST(APPEND BAD_TESTS