From bcd643a2442980db9ed649013ba7884b8391153e Mon Sep 17 00:00:00 2001 From: qingfengxia Date: Fri, 8 Nov 2019 23:37:48 +0000 Subject: [PATCH 1/7] fix missing ngexception.hpp header for netgen 6.2dev --- CMakeLists.txt | 22 +++++++++++++++++---- src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx | 16 ++++++++++++++- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/CMakeLists.txt b/CMakeLists.txt index 85cbe5f..74f4bae 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -24,10 +24,18 @@ set(SMESH_VERSION_TWEAK 3) # Build shared libraries set(BUILD_SHARED_LIBS ON) -# Compiler flags -# if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) -# set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") -# endif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) +# you ccache is installed, use it +find_program(CCACHE_PROGRAM ccache) +if(CCACHE_PROGRAM) + set_property(GLOBAL PROPERTY RULE_LAUNCH_COMPILE "${CCACHE_PROGRAM}") +endif() + +# Compiler flags, c++11 is essential for OCCT 7.3 +# netget 6.2 also need G++6, using `export CXX=g++6` to select compiler +# is that possible to detect OpenCASCADE_VERSION by cmake? +if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") +endif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) # --------------------------------------------------------------------------- # # OpenCASCADE @@ -149,6 +157,10 @@ if(ENABLE_NETGEN) include_directories(${NETGEN_INCLUDE_DIR}/gprim) include_directories(${NETGEN_INCLUDE_DIR}/include) include_directories(${NETGEN_INCLUDE_DIR}/stlgeom) + + #netgen 6.2 has more subfolder for headers + include_directories(${NETGEN_INCLUDE_DIR}/core) + remove_definitions("-DNETGEN_PYTHON") # Set NETGEN_VERSION file(STRINGS ${NETGEN_INCLUDE_DIR}/mydefs.hpp NETGEN_VERSION @@ -336,6 +348,7 @@ if(ENABLE_NETGEN) add_library(NETGENPlugin ${NETGENPlugin_SRC}) if (NETGEN_LIBRARY) target_link_libraries(NETGENPlugin StdMeshers TKIGES TKXDEIGES ${NETGEN_LIBRARY}) + message(STATUS "NETGEN_LIBRARY= ${NETGEN_LIBRARY}") else (NETGEN_LIBRARY) target_link_libraries(NETGENPlugin StdMeshers nglib) endif (NETGEN_LIBRARY) @@ -343,6 +356,7 @@ if(ENABLE_NETGEN) set_target_properties(NETGENPlugin PROPERTIES COMPILE_FLAGS "-DNETGENPLUGIN_EXPORTS -DNO_PARALLEL_THREADS -DOCCGEOMETRY -DNETGEN_VERSION=${NETGEN_VERSION}") else() set_target_properties(NETGENPlugin PROPERTIES COMPILE_FLAGS "${NETGEN_CXX_FLAGS} -DNETGEN_VERSION=${NETGEN_VERSION}") + message(STATUS "NETGEN_CXX_FLAGS= ${NETGEN_CXX_FLAGS}") endif() endif() diff --git a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx index b6b0ce5..25ca893 100644 --- a/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx +++ b/src/NETGENPlugin/NETGENPlugin_NETGEN_3D.cxx @@ -70,8 +70,12 @@ #ifndef OCCGEOMETRY #define OCCGEOMETRY #endif + #include -#include +//#if defined(DLL_HEADER) +//#undef DLL_HEADER +//#endif + namespace nglib { #include } @@ -88,6 +92,16 @@ namespace netgen { DLL_HEADER extern MeshingParameters mparam; DLL_HEADER extern volatile multithreadt multithread; } + +#if NETGEN_VERSION >= NETGEN_VERSION_STRING(6,2) +namespace netgen { + #include + typedef ngcore::Exception NgException; +} +#else +#include +#endif + using namespace nglib; using namespace std; From fa61eb25717c4894fcab023fdc25062a4f915c47 Mon Sep 17 00:00:00 2001 From: qingfengxia Date: Fri, 8 Nov 2019 23:41:45 +0000 Subject: [PATCH 2/7] disable pybind11 by --- inc/NETGENPlugin_Defs.hxx | 2 ++ 1 file changed, 2 insertions(+) diff --git a/inc/NETGENPlugin_Defs.hxx b/inc/NETGENPlugin_Defs.hxx index 1a64251..fd42110 100644 --- a/inc/NETGENPlugin_Defs.hxx +++ b/inc/NETGENPlugin_Defs.hxx @@ -27,6 +27,8 @@ #ifndef _NETGENPlugin_DEFS_HXX_ #define _NETGENPlugin_DEFS_HXX_ +#undef NETGEN_PYTHON + #ifdef WIN32 #if defined NETGENPLUGIN_EXPORTS || defined NETGENEngine_EXPORTS #define NETGENPLUGIN_EXPORT __declspec( dllexport ) From 5ef5b135b682c53d9d2c4a38070931da6af1582d Mon Sep 17 00:00:00 2001 From: "Xia, Qingfeng" Date: Mon, 11 Nov 2019 10:58:47 +0000 Subject: [PATCH 3/7] Add qingfengxia's changelog --- CMakeLists.txt | 8 ++++ smesh_changelog.md | 114 +++++++++++++++++++++++++++++++++++++++++++++ 2 files changed, 122 insertions(+) create mode 100644 smesh_changelog.md diff --git a/CMakeLists.txt b/CMakeLists.txt index 74f4bae..3e6f276 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -346,6 +346,14 @@ endif() if(ENABLE_NETGEN) file(GLOB NETGENPlugin_SRC src/NETGENPlugin/*.cxx) add_library(NETGENPlugin ${NETGENPlugin_SRC}) + # the latest netget 6.2 need C++14 + if (${NETGEN_VERSION} VERSION_GREATER_EQUAL 6.2) + set_target_properties(NETGENPlugin PROPERTIES + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO + ) + endif() if (NETGEN_LIBRARY) target_link_libraries(NETGENPlugin StdMeshers TKIGES TKXDEIGES ${NETGEN_LIBRARY}) message(STATUS "NETGEN_LIBRARY= ${NETGEN_LIBRARY}") diff --git a/smesh_changelog.md b/smesh_changelog.md new file mode 100644 index 0000000..8d0c136 --- /dev/null +++ b/smesh_changelog.md @@ -0,0 +1,114 @@ + + +## Overview + +netgen license? GNU Lesser General Public License v2.1 + +salome 9.3 stills use the netgen 5.5 version + + + +### C++ standard version must support C++14 + +C++11 is reequried by OCCT 7.3 + +while netgen 6.2dev requires C++14, `std::enable_if_t` is not available on g++ 5.x + +```cmake +# netget 6.2 also need g++6, using `export CXX=g++6` to select compiler +# Compiler flags, c++11 is essential for OCCT 7.3 + if (${NETGEN_VERSION} VERSION_GREATER_EQUAL 6.2) + set_target_properties(NETGENPlugin PROPERTIES + CXX_STANDARD 14 + CXX_STANDARD_REQUIRED YES + CXX_EXTENSIONS NO + ) + endif() + +# is that possible to detect OpenCASCADE_VERSION by cmake? +``` + + + +/usr/include/netgen/core/type_traits.hpp:14:20: warning: variable templates only available with -std=c++14 or -std=gnu++14 + constexpr bool all_of_tmpl = std::is_same<_BoolArray, _BoolArray<(vals || true)...>>::value; // NOLINT + + + +### Migration to C++17 + +Salome code is not yet C++17 ready, esp, the breaking exception declearation change in C++17 + +*looo* has started working on `c++17: dynamic exception specification -> noexcept(false)` +https://github.com/LaughlinResearch/SMESH/pull/13 + +However, it seems has not completed + +### Python binding for salomesmesh + +PyOCCT has the binding for salomesmesh, using generated pybind11 wrapping. + + + + +## Changelog + +### missing dependencies +libmetis.so is needed +libtbb-dev is needed, added to *conda*, but it is not mentioned in readme. + + +### smesh cmake failed on windows for `pthread` + +``` +CMake Error at src/3rdParty/salomesmesh/CMakeLists.txt:150 (message): + pthread include directory is required. +``` + +`set(CMAKE_USE_WIN32_THREADS_INIT 1)` + +pthread detect can be removed for windows? +in CMake, `UNIX` cover Linux, MacOS? + +*src file, has projection preprocessor*, but it is also used by several headers + +qingfeng@qingfeng-ubuntu:/opt/SMESH/inc$ grep -rnw ./ -e "pthread" +./BaseTraceCollector.hxx:33:#include +./BasicsGenericDestructor.hxx:40:#include +./LocalTraceBufferPool.hxx:36:#include + +### smesh tweak on windows + +already done for windows + +`MinGW` should work, has it has pthread built in + +https://github.com/LaughlinResearch/SMESH/commit/685632514a06172c16cbf12ee05cf7776998ecd1 +``` +// Keep compatibility with paraview 5.0.1 on Linux +#ifndef WIN32 +//#ifndef WIN32 + #ifndef VTK_HAS_MTIME_TYPE + #define VTK_HAS_MTIME_TYPE + typedef unsigned long int vtkMTimeType; + #endif +#endif +//#endif +``` + +### FreeCAD specific + +https://github.com/qingfengxia/FreeCAD/blob/smesh/cMake/FindSMESH.cmake + +[src/3rdParty/CMakeLists.txt] +FREECAD_USE_EXTERNAL_SMESH + + `SMESH_Version.h.cmake` + + used only in FEM module + +### segment fault during netgen meshing in FreeCAD + +FreeCAD has segment fault with this version of netgen, perhaps it is not patched + +https://forum.freecadweb.org/viewtopic.php?f=4&t=40637&p=346703#p346703 \ No newline at end of file From 0d907ecfef1aa75fd25688e580af12fb6595269f Mon Sep 17 00:00:00 2001 From: "Xia, Qingfeng" Date: Mon, 11 Nov 2019 15:37:33 +0000 Subject: [PATCH 4/7] remove SUIT subfolder GUI filtering related code --- inc/SMESH_LogicalFilter.hxx | 60 ------------------- inc/SMESH_NumberFilter.hxx | 96 ------------------------------- inc/SMESH_TypeFilter.hxx | 47 --------------- src/SUIT/SUIT_SelectionFilter.cxx | 32 ----------- 4 files changed, 235 deletions(-) delete mode 100644 inc/SMESH_LogicalFilter.hxx delete mode 100644 inc/SMESH_NumberFilter.hxx delete mode 100644 inc/SMESH_TypeFilter.hxx delete mode 100644 src/SUIT/SUIT_SelectionFilter.cxx diff --git a/inc/SMESH_LogicalFilter.hxx b/inc/SMESH_LogicalFilter.hxx deleted file mode 100644 index 3a5a9b2..0000000 --- a/inc/SMESH_LogicalFilter.hxx +++ /dev/null @@ -1,60 +0,0 @@ -// Copyright (C) 2007-2016 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_LogicalFilter.hxx -// Module : SMESH -// -#ifndef _SMESH_LogicalFilter_HeaderFile -#define _SMESH_LogicalFilter_HeaderFile - -#include "SMESH_Type.h" - -#include - -#include - -class SMESHFILTERSSELECTION_EXPORT SMESH_LogicalFilter : public SUIT_SelectionFilter -{ - public: - enum { LO_OR, LO_AND, LO_NOT, LO_UNDEFINED }; - - public: - SMESH_LogicalFilter( const QList&, const int, bool takeOwnership=false ); - virtual ~SMESH_LogicalFilter(); - - virtual bool isOk (const SUIT_DataOwner*) const; - - void setFilters (const QList&); - void setOperation (const int); - const QList getFilters() const; - int getOperation() const; - -private: - void deleteFilters(); - -private: - QList myFilters; - int myOperation; - bool myOwnership; -}; - -#endif diff --git a/inc/SMESH_NumberFilter.hxx b/inc/SMESH_NumberFilter.hxx deleted file mode 100644 index b7ae5d5..0000000 --- a/inc/SMESH_NumberFilter.hxx +++ /dev/null @@ -1,96 +0,0 @@ -// Copyright (C) 2007-2016 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_NumberFilter.hxx -// Module : SMESH -// -#ifndef _SMESH_NumberFilter_HeaderFile -#define _SMESH_NumberFilter_HeaderFile - -#include "SMESH_Type.h" - -#include "SUIT_SelectionFilter.h" - -#include -#include - -#include -#include CORBA_SERVER_HEADER(GEOM_Gen) - -#include - -class SUIT_DataOwner; - -/*! - * Class : SMESH_NumberFilter - * Description : Filter for geom or smesh objects. - * Filter geom objects by number of subshapes of the given type - * Parameters of constructor: - * * theSubShapeType - Type of subshape - * * theNumber - Number of subshapes. Object is selected if it contains - * theNumber of theSubShapeType sub-shapes, or at least - * one theSubShapeType, provided that theNumber==0 - * * theShapeType - This map specifies types of object to be selected - * * theMainObject - Sub-shapes of this object is selected only - * * theIsClosedOnly - Closed shapes is selected if this parameter is true - */ -class SMESHFILTERSSELECTION_EXPORT SMESH_NumberFilter : public SUIT_SelectionFilter -{ - public: - SMESH_NumberFilter (const char* theKind, - const TopAbs_ShapeEnum theSubShapeType, - const int theNumber, - const TopAbs_ShapeEnum theShapeType = TopAbs_SHAPE, - GEOM::GEOM_Object_ptr theMainObj = GEOM::GEOM_Object::_nil(), - const bool theIsClosedOnly = false ); - - SMESH_NumberFilter (const char* theKind, - const TopAbs_ShapeEnum theSubShapeType, - const int theNumber, - const TColStd_MapOfInteger& theShapeTypes, - GEOM::GEOM_Object_ptr theMainObj = GEOM::GEOM_Object::_nil(), - const bool theIsClosedOnly = false ); - - virtual ~SMESH_NumberFilter(); - - virtual bool isOk (const SUIT_DataOwner*) const; - - void SetSubShapeType (const TopAbs_ShapeEnum); - void SetNumber (const int); - void SetClosedOnly (const bool); - void SetShapeType (const TopAbs_ShapeEnum); - void SetShapeTypes (const TColStd_MapOfInteger&); - void SetMainShape (GEOM::GEOM_Object_ptr); - - private: - GEOM::GEOM_Object_ptr getGeom (const SUIT_DataOwner*, const bool extractReference = true ) const; - - private: - std::string myKind; - TopAbs_ShapeEnum mySubShapeType; - int myNumber; - bool myIsClosedOnly; - TColStd_MapOfInteger myShapeTypes; - GEOM::GEOM_Object_var myMainObj; -}; - -#endif diff --git a/inc/SMESH_TypeFilter.hxx b/inc/SMESH_TypeFilter.hxx deleted file mode 100644 index 85d99b6..0000000 --- a/inc/SMESH_TypeFilter.hxx +++ /dev/null @@ -1,47 +0,0 @@ -// Copyright (C) 2007-2016 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_TypeFilter.hxx -// Module : SMESH -// -#ifndef _SMESH_TypeFilter_HeaderFile -#define _SMESH_TypeFilter_HeaderFile - -#include "SMESH_Type.h" -#include "SUIT_SelectionFilter.h" - -class SUIT_DataOwner; - -class SMESHFILTERSSELECTION_EXPORT SMESH_TypeFilter : public SUIT_SelectionFilter -{ -public: - SMESH_TypeFilter (SMESH::MeshObjectType theType); - ~SMESH_TypeFilter(); - - virtual bool isOk (const SUIT_DataOwner*) const; - SMESH::MeshObjectType type() const; - -protected: - SMESH::MeshObjectType myType; -}; - -#endif diff --git a/src/SUIT/SUIT_SelectionFilter.cxx b/src/SUIT/SUIT_SelectionFilter.cxx deleted file mode 100644 index 21301f8..0000000 --- a/src/SUIT/SUIT_SelectionFilter.cxx +++ /dev/null @@ -1,32 +0,0 @@ -// Copyright (C) 2007-2016 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 -// - -#include "SUIT_SelectionFilter.h" - -/*! constructor. do nothing*/ -SUIT_SelectionFilter::SUIT_SelectionFilter() -{ -} -/*! destructor. do nothing*/ -SUIT_SelectionFilter::~SUIT_SelectionFilter() -{ -} From 0cbb74ccb7b429a4c709161cefe0eefeaa10763d Mon Sep 17 00:00:00 2001 From: "Xia, Qingfeng" Date: Mon, 11 Nov 2019 15:56:14 +0000 Subject: [PATCH 5/7] rename Utils to SMESHUtils as in salome mesh module --- src/{Utils => SMESHUtils}/SMESH_Block.cxx | 0 src/{Utils => SMESHUtils}/SMESH_ControlPnt.cxx | 0 src/{Utils => SMESHUtils}/SMESH_DeMerge.cxx | 0 src/{Utils => SMESHUtils}/SMESH_File.cxx | 0 src/{Utils => SMESHUtils}/SMESH_FreeBorders.cxx | 0 src/{Utils => SMESHUtils}/SMESH_MAT2d.cxx | 0 src/{Utils => SMESHUtils}/SMESH_MeshAlgos.cxx | 0 src/{Utils => SMESHUtils}/SMESH_Octree.cxx | 0 src/{Utils => SMESHUtils}/SMESH_OctreeNode.cxx | 0 src/{Utils => SMESHUtils}/SMESH_Quadtree.cxx | 0 src/{Utils => SMESHUtils}/SMESH_TryCatch.cxx | 0 11 files changed, 0 insertions(+), 0 deletions(-) rename src/{Utils => SMESHUtils}/SMESH_Block.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_ControlPnt.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_DeMerge.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_File.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_FreeBorders.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_MAT2d.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_MeshAlgos.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_Octree.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_OctreeNode.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_Quadtree.cxx (100%) rename src/{Utils => SMESHUtils}/SMESH_TryCatch.cxx (100%) diff --git a/src/Utils/SMESH_Block.cxx b/src/SMESHUtils/SMESH_Block.cxx similarity index 100% rename from src/Utils/SMESH_Block.cxx rename to src/SMESHUtils/SMESH_Block.cxx diff --git a/src/Utils/SMESH_ControlPnt.cxx b/src/SMESHUtils/SMESH_ControlPnt.cxx similarity index 100% rename from src/Utils/SMESH_ControlPnt.cxx rename to src/SMESHUtils/SMESH_ControlPnt.cxx diff --git a/src/Utils/SMESH_DeMerge.cxx b/src/SMESHUtils/SMESH_DeMerge.cxx similarity index 100% rename from src/Utils/SMESH_DeMerge.cxx rename to src/SMESHUtils/SMESH_DeMerge.cxx diff --git a/src/Utils/SMESH_File.cxx b/src/SMESHUtils/SMESH_File.cxx similarity index 100% rename from src/Utils/SMESH_File.cxx rename to src/SMESHUtils/SMESH_File.cxx diff --git a/src/Utils/SMESH_FreeBorders.cxx b/src/SMESHUtils/SMESH_FreeBorders.cxx similarity index 100% rename from src/Utils/SMESH_FreeBorders.cxx rename to src/SMESHUtils/SMESH_FreeBorders.cxx diff --git a/src/Utils/SMESH_MAT2d.cxx b/src/SMESHUtils/SMESH_MAT2d.cxx similarity index 100% rename from src/Utils/SMESH_MAT2d.cxx rename to src/SMESHUtils/SMESH_MAT2d.cxx diff --git a/src/Utils/SMESH_MeshAlgos.cxx b/src/SMESHUtils/SMESH_MeshAlgos.cxx similarity index 100% rename from src/Utils/SMESH_MeshAlgos.cxx rename to src/SMESHUtils/SMESH_MeshAlgos.cxx diff --git a/src/Utils/SMESH_Octree.cxx b/src/SMESHUtils/SMESH_Octree.cxx similarity index 100% rename from src/Utils/SMESH_Octree.cxx rename to src/SMESHUtils/SMESH_Octree.cxx diff --git a/src/Utils/SMESH_OctreeNode.cxx b/src/SMESHUtils/SMESH_OctreeNode.cxx similarity index 100% rename from src/Utils/SMESH_OctreeNode.cxx rename to src/SMESHUtils/SMESH_OctreeNode.cxx diff --git a/src/Utils/SMESH_Quadtree.cxx b/src/SMESHUtils/SMESH_Quadtree.cxx similarity index 100% rename from src/Utils/SMESH_Quadtree.cxx rename to src/SMESHUtils/SMESH_Quadtree.cxx diff --git a/src/Utils/SMESH_TryCatch.cxx b/src/SMESHUtils/SMESH_TryCatch.cxx similarity index 100% rename from src/Utils/SMESH_TryCatch.cxx rename to src/SMESHUtils/SMESH_TryCatch.cxx From 9243a1531c23660b1552edbd472ce2dfb877c15a Mon Sep 17 00:00:00 2001 From: "Xia, Qingfeng" Date: Mon, 11 Nov 2019 16:55:34 +0000 Subject: [PATCH 6/7] add CGNS driver for mesh IO --- CMakeLists.txt | 60 +- cmake/FindCGNS.cmake | 48 + inc/DriverCGNS_Read.hxx | 59 ++ inc/DriverCGNS_Write.hxx | 53 ++ inc/SMESH_DriverCGNS.hxx | 0 src/DriverCGNS/DriverCGNS_Read.cxx | 1252 +++++++++++++++++++++++++++ src/DriverCGNS/DriverCGNS_Write.cxx | 606 +++++++++++++ 7 files changed, 2067 insertions(+), 11 deletions(-) create mode 100644 cmake/FindCGNS.cmake create mode 100644 inc/DriverCGNS_Read.hxx create mode 100644 inc/DriverCGNS_Write.hxx mode change 100644 => 100755 inc/SMESH_DriverCGNS.hxx create mode 100644 src/DriverCGNS/DriverCGNS_Read.cxx create mode 100644 src/DriverCGNS/DriverCGNS_Write.cxx diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e6f276..5ee39da 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -2,13 +2,16 @@ cmake_minimum_required(VERSION 3.3) project(SMESH C CXX) +set(CMAKE_MODULE_PATH "${PROJECT_SOURCE_DIR}/cmake" ${CMAKE_MODULE_PATH}) # --------------------------------------------------------------------------- # # OPTIONS # --------------------------------------------------------------------------- # -option(ENABLE_NETGEN "Enable NETGEN" ON) -option(ENABLE_MED "Enable MED" OFF) -option(ENABLE_BLSURF "Enable BLSURF" OFF) +option(ENABLE_NETGEN "Enable NETGEN mesher" ON) +option(ENABLE_MED "Enable MED mesh format IO" OFF) +option(ENABLE_CGNS "Enable CGNS mesh format input and output " ON) +option(ENABLE_BLSURF "Enable BLSURF mesher" OFF) option(ENABLE_LIB_NAMING "Enable additional library naming" OFF) + set(CMAKE_INSTALL_PREFIX "${CMAKE_SOURCE_DIR}/install" CACHE PATH "Installation directory.") set(CMAKE_INSTALL_LIBDIR lib CACHE PATH "Output directory for libraries") @@ -34,7 +37,7 @@ endif() # netget 6.2 also need G++6, using `export CXX=g++6` to select compiler # is that possible to detect OpenCASCADE_VERSION by cmake? if(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) - set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++14") + set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -std=c++11") endif(CMAKE_COMPILER_IS_GNUCXX OR CMAKE_COMPILER_IS_CLANGXX) # --------------------------------------------------------------------------- # @@ -224,16 +227,35 @@ if(ENABLE_MED) message(FATAL_ERROR "Failed to find MED include directories.") endif() - if(NOT EXISTS ${MEDFILE_INCLUDE_DIRS}) - message(FATAL_ERROR "Failed to find MED librar directory.") - endif() - message(STATUS "MED include directory: ${MED_INCLUDE_DIR}") message(STATUS "MED library directory: ${MED_LIBRARY_DIR}") include_directories(${MEDFILE_INCLUDE_DIRS}) endif() +# --------------------------------------------------------------------------- # +# CGNS +# --------------------------------------------------------------------------- # +if(ENABLE_CGNS) + if(NOT DEFINED CGNS_INCLUDE_DIRS OR NOT DEFINED CGNS_LIBRARY_DIR) + message(STATUS "Searching for CGNS...") + find_package(CGNS) # REQUIRED + endif() + + if(NOT EXISTS ${CGNS_INCLUDE_DIRS}) + message(FATAL_ERROR "Failed to find CGNS include directories.") + endif() + + if(NOT EXISTS ${CGNS_INCLUDE_DIRS}) + message(FATAL_ERROR "Failed to find CGNS librar directory.") + endif() + + message(STATUS "CGNS include directory: ${CGNS_INCLUDE_DIR}") + message(STATUS "CGNS library directory: ${CGNS_LIBRARY_DIR}") + include_directories(${CGNS_INCLUDE_DIRS}) +endif() + + # --------------------------------------------------------------------------- # # SMESH # --------------------------------------------------------------------------- # @@ -326,6 +348,18 @@ if(ENABLE_MED) endif() endif() +# DriverCGNS +if(UNIX) +if(ENABLE_CGNS) + file(GLOB DriverCGNS_SRC src/DriverCGNS/*.cxx) + add_library(DriverCGNS ${DriverCGNS_SRC}) + target_link_libraries(DriverCGNS SMDS Driver SMESHMisc SMESHTrace SMESHBasics ${CGNSFILE_LIBRARIES}) + if(WIN32) + set_target_properties(DriverCGNS PROPERTIES COMPILE_FLAGS "-MESHDRIVERCGNS_EXPORT") + endif() +endif() +endif() + # MEFISTO2 file(GLOB MEFISTO2_SRC src/MEFISTO2/aptrte.cxx src/MEFISTO2/trte.c) add_library(MEFISTO2 ${MEFISTO2_SRC}) @@ -402,7 +436,7 @@ else() set_target_properties(StdMeshers PROPERTIES COMPILE_FLAGS "${StdMeshers_CFLAGS}") endif() -# Trace +# Salome kernel's Trace file(GLOB Trace_SRC src/Trace/*.cxx) add_library(SMESHTrace ${Trace_SRC}) if(UNIX) @@ -414,8 +448,8 @@ if(WIN32) set_target_properties(SMESHTrace PROPERTIES COMPILE_FLAGS "-DSALOMELOCALTRACE_EXPORTS") endif() -# Utils -file(GLOB Utils_SRC src/Utils/*.cxx) +# SMESHUtils +file(GLOB Utils_SRC src/SMESHUtils/*.cxx) add_library(SMESHUtils ${Utils_SRC}) target_link_libraries(SMESHUtils SMDS TKShHealing TKPrim TKernel TKBRep TKG2d TKG3d TKGeomBase TKGeomAlgo TKTopAlgo TKMesh ${Boost_LIBRARIES}) if(WIN32) @@ -448,6 +482,10 @@ if(ENABLE_MED) set(SMESH_LIBRARIES ${SMESH_LIBRARIES} DriverMED) endif() +if(ENABLE_CGNS) + set(SMESH_LIBRARIES ${SMESH_LIBRARIES} DriverCGNS) +endif() + if (MSVC AND ENABLE_LIB_NAMING) foreach(it ${SMESH_LIBRARIES}) LIST(APPEND SMESH_LIBS "optimized ${it}") diff --git a/cmake/FindCGNS.cmake b/cmake/FindCGNS.cmake new file mode 100644 index 0000000..005f1af --- /dev/null +++ b/cmake/FindCGNS.cmake @@ -0,0 +1,48 @@ +# +# Find the native CGNS includes and library +# +# CGNS_INCLUDE_DIR - where to find cgns.h, etc. +# CGNS_LIBRARIES - List of fully qualified libraries to link against when using CGNS. +# CGNS_FOUND - Do not attempt to use CGNS if "no" or undefined. + +find_path(CGNS_INCLUDE_DIR + NAMES + cgnslib.h + PATHS + /usr/local/include + /usr/include + DOC "CGNS include directory") +mark_as_advanced(CGNS_INCLUDE_DIR) + +find_library(CGNS_LIBRARY + NAMES + cgns + DOC "CGNS library") +mark_as_advanced(CGNS_LIBRARY) + +if (CGNS_INCLUDE_DIR) + file(STRINGS "${CGNS_INCLUDE_DIR}/cgnslib.h" version + REGEX "CGNS_DOTVERS") + string(REGEX REPLACE ".*CGNS_DOTVERS *\([0-9.]*\).*" "\\1" CGNS_VERSION "${version}") + unset(version) +else () + set(CGNS_VERSION CGNS_VERSION-NOTFOUND) +endif () + +# handle the QUIETLY and REQUIRED arguments and set CGNS_FOUND to TRUE if +# all listed variables are TRUE +include(FindPackageHandleStandardArgs) +find_package_handle_standard_args(CGNS + REQUIRED_VARS CGNS_INCLUDE_DIR CGNS_LIBRARY + VERSION_VAR CGNS_VERSION) + +if (CGNS_FOUND) + set(CGNS_LIBRARIES "${CGNS_LIBRARY}") + set(CGNS_INCLUDE_DIRS "${CGNS_INCLUDE_DIR}") + if (NOT TARGET CGNS::CGNS) + add_library(CGNS::CGNS UNKNOWN IMPORTED) + set_target_properties(CGNS::CGNS PROPERTIES + IMPORTED_LOCATION "${CGNS_LIBRARY}" + INTERFACE_INCLUDE_DIRECTORIES "${CGNS_INCLUDE_DIR}") + endif () +endif () diff --git a/inc/DriverCGNS_Read.hxx b/inc/DriverCGNS_Read.hxx new file mode 100644 index 0000000..682ff16 --- /dev/null +++ b/inc/DriverCGNS_Read.hxx @@ -0,0 +1,59 @@ +// Copyright (C) 2007-2016 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 : DriverCGNS_Read.hxx +// Created : Thu Jun 30 10:25:09 2011 +// Author : Edward AGAPOV (eap) + +#ifndef __DriverCGNS_Read_HXX__ +#define __DriverCGNS_Read_HXX__ + +#include "SMESH_DriverCGNS.hxx" + +#include "Driver_SMESHDS_Mesh.h" + +#include +#include + +/*! + * \brief Driver reading a mesh from the CGNS file. The mesh to read is selected by + * an index (counted from 0) set via SetMeshId() + */ +class MESHDriverCGNS_EXPORT DriverCGNS_Read : public Driver_SMESHDS_Mesh +{ +public: + + DriverCGNS_Read(); + ~DriverCGNS_Read(); + + virtual Status Perform(); + + int GetNbMeshes(Status& theStatus); + + +private: + + Status open(); + + int _fn; //!< file index +}; + +#endif diff --git a/inc/DriverCGNS_Write.hxx b/inc/DriverCGNS_Write.hxx new file mode 100644 index 0000000..e427f97 --- /dev/null +++ b/inc/DriverCGNS_Write.hxx @@ -0,0 +1,53 @@ +// Copyright (C) 2007-2016 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 : DriverCGNS_Write.hxx +// Created : Thu Jun 30 10:25:09 2011 +// Author : Edward AGAPOV (eap) + +#ifndef __DriverCGNS_Write_HXX__ +#define __DriverCGNS_Write_HXX__ + +#include "SMESH_DriverCGNS.hxx" + +#include "Driver_SMESHDS_Mesh.h" + +#include +#include + +/*! + * \brief Driver writinging a mesh into the CGNS file. + */ +class MESHDriverCGNS_EXPORT DriverCGNS_Write : public Driver_SMESHDS_Mesh +{ +public: + + DriverCGNS_Write(); + ~DriverCGNS_Write(); + + virtual Status Perform(); + +private: + + int _fn; //!< file index +}; + +#endif diff --git a/inc/SMESH_DriverCGNS.hxx b/inc/SMESH_DriverCGNS.hxx old mode 100644 new mode 100755 diff --git a/src/DriverCGNS/DriverCGNS_Read.cxx b/src/DriverCGNS/DriverCGNS_Read.cxx new file mode 100644 index 0000000..c784acc --- /dev/null +++ b/src/DriverCGNS/DriverCGNS_Read.cxx @@ -0,0 +1,1252 @@ +// Copyright (C) 2007-2016 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 : DriverCGNS_Read.cxx +// Created : Thu Jun 30 10:33:31 2011 +// Author : Edward AGAPOV (eap) + +#include "DriverCGNS_Read.hxx" + +#include "SMDS_MeshNode.hxx" +#include "SMESHDS_Group.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" +#include "SMESH_TypeDefs.hxx" + +#include + +#include + +#include + +#if CGNS_VERSION < 3100 +# define cgsize_t int +#endif + +#define NB_ZONE_SIZE_VAL 9 +#define CGNS_NAME_SIZE 33 +#define CGNS_STRUCT_RANGE_SZ 6 + +using namespace std; + +namespace +{ + //================================================================================ + /*! + * \brief Data of a zone + */ + struct TZoneData + { + int _id; + int _nodeIdShift; // nb nodes in previously read zones + int _elemIdShift; // nb faces in previously read zones + int _nbNodes, _nbElems; + int _meshDim; + int _sizeX, _sizeY, _sizeZ, _nbCells; // structured + cgsize_t _sizes[NB_ZONE_SIZE_VAL]; + CGNS_ENUMT(ZoneType_t) _type; + map< int, int > _nodeReplacementMap;/* key: id of node to replace (in this zone), + value: id of node to replace by (in another zone) + id values include _nodeIdShift of the zones */ + void SetSizeAndDim( cgsize_t* sizes, int meshDim ) + { + _meshDim = meshDim; + memcpy( _sizes, sizes, NB_ZONE_SIZE_VAL*sizeof(cgsize_t)); + _sizeX = _sizes[0]; + _sizeY = _meshDim > 1 ? _sizes[1] : 0; + _sizeZ = _meshDim > 2 ? _sizes[2] : 0; + _nbCells = (_sizeX - 1) * ( _meshDim > 1 ? _sizeY : 1 ) * ( _meshDim > 2 ? _sizeZ : 1 ); + } + bool IsStructured() const { return ( _type == CGNS_ENUMV( Structured )); } + int IndexSize() const { return IsStructured() ? _meshDim : 1; } + string ReadZonesConnection(int file, int base, + const map< string, TZoneData >& zonesByName, + SMESHDS_Mesh* mesh); + void ReplaceNodes( cgsize_t* ids, int nbIds, int idShift = 0 ) const; + + // Methods for a structured zone + + int NodeID( int i, int j, int k = 1 ) const + { + return _nodeIdShift + (k-1)*_sizeX*_sizeY + (j-1)*_sizeX + i; + } + int NodeID( const gp_XYZ& ijk ) const + { + return NodeID( int(ijk.X()), int(ijk.Y()), int(ijk.Z())); + } + void CellNodes( int i, int j, int k, cgsize_t* ids ) const + { + ids[0] = NodeID( i , j , k ); + ids[1] = NodeID( i , j+1, k ); + ids[2] = NodeID( i+1, j+1, k ); + ids[3] = NodeID( i+1, j , k ); + ids[4] = NodeID( i , j , k+1); + ids[5] = NodeID( i , j+1, k+1); + ids[6] = NodeID( i+1, j+1, k+1); + ids[7] = NodeID( i+1, j , k+1); + } + void CellNodes( int i, int j, cgsize_t* ids ) const + { + ids[0] = NodeID( i , j ); + ids[1] = NodeID( i , j+1 ); + ids[2] = NodeID( i+1, j+1 ); + ids[3] = NodeID( i+1, j ); + } + void IFaceNodes( int i, int j, int k, cgsize_t* ids ) const // face perpendiculaire to X (3D) + { + ids[0] = NodeID( i, j, k ); + ids[1] = ids[0] + _sizeX*( i==_sizeX ? 1 : _sizeY ); + ids[2] = ids[0] + _sizeX*( _sizeY + 1 ); + ids[3] = ids[0] + _sizeX*( i==_sizeX ? _sizeY : 1 ); + } + void JFaceNodes( int i, int j, int k, cgsize_t* ids ) const + { + ids[0] = NodeID( i, j, k ); + ids[1] = ids[0] + ( j==_sizeY ? _sizeX*_sizeY : 1); + ids[2] = ids[0] + _sizeX*_sizeY + 1; + ids[3] = ids[0] + ( j==_sizeY ? 1 : _sizeX*_sizeY); + } + void KFaceNodes( int i, int j, int k, cgsize_t* ids ) const + { + ids[0] = NodeID( i, j, k ); + ids[1] = ids[0] + ( k==_sizeZ ? 1 : _sizeX); + ids[2] = ids[0] + _sizeX + 1; + ids[3] = ids[0] + ( k==_sizeZ ? _sizeX : 1); + } + void IEdgeNodes( int i, int j, int k, cgsize_t* ids ) const // edge perpendiculaire to X (2D) + { + ids[0] = NodeID( i, j, 0 ); + ids[1] = ids[0] + _sizeX; + } + void JEdgeNodes( int i, int j, int k, cgsize_t* ids ) const + { + ids[0] = NodeID( i, j, 0 ); + ids[1] = ids[0] + 1; + } +#define gpXYZ2IJK(METHOD) \ + void METHOD( const gp_XYZ& ijk, cgsize_t* ids ) const { \ + METHOD( int(ijk.X()), int(ijk.Y()), int(ijk.Z()), ids); \ + } + gpXYZ2IJK( IFaceNodes ) + gpXYZ2IJK( JFaceNodes ) + gpXYZ2IJK( KFaceNodes ) + gpXYZ2IJK( IEdgeNodes ) + gpXYZ2IJK( JEdgeNodes ) + }; + + //================================================================================ + /*! + * \brief Iterator over nodes of the structired grid using FORTRAN multidimensional + * array ordering. + */ + class TPointRangeIterator + { + int _beg[3], _end[3], _cur[3], _dir[3], _dim; + bool _more; + public: + TPointRangeIterator( const cgsize_t* range, int dim ):_dim(dim) + { + _more = false; + for ( int i = 0; i < dim; ++i ) + { + _beg[i] = range[i]; + _end[i] = range[i+dim]; + _dir[i] = _end[i] < _beg[i] ? -1 : 1; + _end[i] += _dir[i]; + _cur[i] = _beg[i]; + if ( _end[i] - _beg[i] ) + _more = true; + } +// for ( int i = dim; i < 3; ++i ) +// _cur[i] = _beg[i] = _end[i] = _dir[i] = 0; + } + bool More() const + { + return _more; + } + gp_XYZ Next() + { + gp_XYZ res( _cur[0], _cur[1], _cur[2] ); + for ( int i = 0; i < _dim; ++i ) + { + _cur[i] += _dir[i]; + if ( _cur[i]*_dir[i] < _end[i]*_dir[i] ) + break; + if ( i+1 < _dim ) + _cur[i] = _beg[i]; + else + _more = false; + } + return res; + } + size_t Size() const + { + size_t size = 1; + for ( int i = 0; i < _dim; ++i ) + size *= _dir[i]*(_end[i]-_beg[i]); + return size; + } + gp_XYZ Begin() const { return gp_XYZ( _beg[0], _beg[1], _beg[2] ); } + //gp_XYZ End() const { return gp_XYZ( _end[0]-1, _end[1]-1, _end[2]-1 ); } + }; + + //================================================================================ + /*! + * \brief Checks if the two arrays of node IDs describe nodes with equal coordinates + */ + //================================================================================ + + bool isEqualNodes( const int* nIds1, const int* nIds2, int nbNodes, SMESHDS_Mesh* mesh ) + { + if ( nbNodes > 0 ) + { + SMESH_TNodeXYZ nn1[2], nn2[2]; + nn1[0] = mesh->FindNode( nIds1[0] ); + nn2[0] = mesh->FindNode( nIds2[0] ); + if ( !nn1[0]._node || !nn2[0]._node ) + return false; + double dist1 = ( nn1[0] - nn2[0] ).Modulus(); + double dist2 = 0, tol = 1e-7; + if ( nbNodes > 1 ) + { + nn1[1] = mesh->FindNode( nIds1[1] ); + nn2[1] = mesh->FindNode( nIds2[1] ); + if ( !nn1[1]._node || !nn2[1]._node ) + return false; + dist2 = ( nn1[1] - nn2[1] ).Modulus(); + tol = 1e-5 * ( nn1[0] - nn1[1] ).Modulus(); + } + return ( dist1 < tol && dist2 < tol ); + } + return false; + } + + //================================================================================ + /*! + * \brief Reads zone interface connectivity + * \param file - file to read + * \param base - base to read + * \param zone - zone to replace nodes in + * \param zonesByName - TZoneData by name + * \retval string - warning message + * + * see // http://www.grc.nasa.gov/WWW/cgns/CGNS_docs_current/sids/cnct.html + */ + //================================================================================ + + string TZoneData::ReadZonesConnection( int file, + int base, + const map< string, TZoneData >& zonesByName, + SMESHDS_Mesh* mesh) + { + string error; + + char connectName[ CGNS_NAME_SIZE ], donorName [ CGNS_NAME_SIZE ]; + + // ---------------------------- + // read zone 1 to 1 interfaces + // ---------------------------- + if ( IsStructured() ) + { + int nb1to1 = 0; + if ( cg_n1to1 ( file, base, _id, &nb1to1) == CG_OK ) + { + cgsize_t range[CGNS_STRUCT_RANGE_SZ], donorRange[CGNS_STRUCT_RANGE_SZ]; + int transform[3] = {0,0,0}; + + for ( int I = 1; I <= nb1to1; ++I ) + { + if ( cg_1to1_read(file, base, _id, I, connectName, + donorName, range, donorRange, transform) == CG_OK ) + { + map< string, TZoneData>::const_iterator n_z = zonesByName.find( donorName ); + if ( n_z == zonesByName.end() ) + continue; // donor zone not yet read + const TZoneData& zone2 = n_z->second; + + // set up matrix to transform ijk of the zone to ijk of the zone2 + gp_Mat T; + for ( int i = 0; i < _meshDim; ++i ) + if ( transform[i] ) + { + int row = Abs(transform[i]); + int col = i+1; + int val = transform[i] > 0 ? +1 : -1; + T( row, col ) = val; + } + + // fill nodeReplacementMap + TPointRangeIterator rangeIt1( range, _meshDim ); + TPointRangeIterator rangeIt2( donorRange, _meshDim ); + gp_XYZ begin1 = rangeIt1.Begin(), begin2 = rangeIt2.Begin(), index1, index2; + if ( &zone2 == this ) + { + // not to read twice the same interface with self + TPointRangeIterator rangeIt1bis( range, _meshDim ); + if ( rangeIt1bis.More() ) + { + index1 = rangeIt1bis.Next(); + index2 = T * ( index1 - begin1 ) + begin2; + int node1 = NodeID( index1 ); + int node2 = zone2.NodeID( index2 ); + if ( _nodeReplacementMap.count( node2 ) && + _nodeReplacementMap[ node2 ] == node1 ) + continue; // this interface already read + } + } + // check if range and donorRange describe the same nodes + { + int ids1[2], ids2[2], nbN = 0; + TPointRangeIterator rangeIt1bis( range, _meshDim ); + index1 = rangeIt1bis.Next(); + index2 = T * ( index1 - begin1 ) + begin2; + ids1[0] = NodeID( index1 ); + ids2[0] = zone2.NodeID( index2 ); + ++nbN; + if ( rangeIt1bis.More() ) + { + index1 = rangeIt1bis.Next(); + index2 = T * ( index1 - begin1 ) + begin2; + ids1[1] = NodeID( index1 ); + ids2[1] = zone2.NodeID( index2 ); + ++nbN; + } + if ( !isEqualNodes( &ids1[0], &ids2[0], nbN, mesh )) + continue; + } + while ( rangeIt1.More() ) + { + index1 = rangeIt1.Next(); + index2 = T * ( index1 - begin1 ) + begin2; + int node1 = NodeID( index1 ); + int node2 = zone2.NodeID( index2 ); + _nodeReplacementMap.insert( make_pair( node1, node2 )); + } + } + else + { + error = cg_get_error(); + } + } + } + else + { + error = cg_get_error(); + } + } + + // --------------------------------- + // read general zone connectivities + // --------------------------------- + int nbConn = 0; + if ( cg_nconns( file, base, _id, &nbConn) == CG_OK ) + { + cgsize_t nb, donorNb; + CGNS_ENUMT(GridLocation_t) location; + CGNS_ENUMT(GridConnectivityType_t) connectType; + CGNS_ENUMT(PointSetType_t) ptype, donorPtype; + CGNS_ENUMT(ZoneType_t) donorZonetype; + CGNS_ENUMT(DataType_t) donorDatatype; + + for ( int I = 1; I <= nbConn; ++I ) + { + if ( cg_conn_info(file, base, _id, I, connectName, &location, &connectType, + &ptype, &nb, donorName, &donorZonetype, &donorPtype, + &donorDatatype, &donorNb ) == CG_OK ) + { + if ( location != CGNS_ENUMV( Vertex )) + continue; // we do not support cell-to-cell connectivity + if ( ptype != CGNS_ENUMV( PointList ) && + ptype != CGNS_ENUMV( PointRange )) + continue; + if ( donorPtype != CGNS_ENUMV( PointList ) && + donorPtype != CGNS_ENUMV( PointRange )) + continue; + + map< string, TZoneData>::const_iterator n_z = zonesByName.find( donorName ); + if ( n_z == zonesByName.end() ) + continue; // donor zone not yet read + const TZoneData& zone2 = n_z->second; + + vector< cgsize_t > ids( nb * IndexSize() ); + vector< cgsize_t > donorIds( donorNb * zone2.IndexSize() ); + if (cg_conn_read ( file, base, _id, I, + &ids[0], CGNS_ENUMV(Integer), &donorIds[0]) == CG_OK ) + { + for ( int isThisZone = 0; isThisZone < 2; ++isThisZone ) + { + const TZoneData& zone = isThisZone ? *this : zone2; + CGNS_ENUMT(PointSetType_t) type = isThisZone ? ptype : donorPtype; + vector< cgsize_t >& points = isThisZone ? ids : donorIds; + if ( type == CGNS_ENUMV( PointRange )) + { + TPointRangeIterator rangeIt( &points[0], zone._meshDim ); + points.clear(); + while ( rangeIt.More() ) + points.push_back ( NodeID( rangeIt.Next() )); + } + else if ( zone.IsStructured() ) + { + vector< cgsize_t > resIDs; resIDs.reserve( points.size() / IndexSize() ); + for ( size_t i = 0; i < points.size(); i += IndexSize() ) + resIDs.push_back( zone.NodeID( points[i+0], points[i+1], points[i+2] )); + resIDs.swap( points ); + } + else if ( zone._nodeIdShift > 0 ) + { + for ( size_t i = 0; i < points.size(); ++i ) + points[i] += zone._nodeIdShift; + } + } + size_t nbN = std::min( ids.size(), donorIds.size()); + if ( isEqualNodes( &ids[0], &donorIds[0], nbN, mesh )) + for ( size_t i = 0; i < nbN; ++i ) + _nodeReplacementMap.insert( make_pair( ids[i], donorIds[i] )); + } + else + { + error = cg_get_error(); + } + } + else + { + error = cg_get_error(); + } + } + } + else + { + error = cg_get_error(); + } + return error; + } + + //================================================================================ + /*! + * \brief Replaces node ids according to nodeReplacementMap to take into account + * connection of zones + */ + //================================================================================ + + void TZoneData::ReplaceNodes( cgsize_t* ids, int nbIds, int idShift/* = 0*/ ) const + { + if ( !_nodeReplacementMap.empty() ) + { + map< int, int >::const_iterator it, end = _nodeReplacementMap.end(); + for ( int i = 0; i < nbIds; ++i ) + if (( it = _nodeReplacementMap.find( ids[i] + idShift)) != end ) + ids[i] = it->second; + else + ids[i] += idShift; + } + else if ( idShift ) + { + for ( int i = 0; i < nbIds; ++i ) + ids[i] += idShift; + } + } + //================================================================================ + /*! + * \brief functions adding an element of a particular type + */ + SMDS_MeshElement* add_0D(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->Add0DElementWithID( ids[0], ID ); + } + SMDS_MeshElement* add_BAR_2(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddEdgeWithID( ids[0], ids[1], ID ); + } + SMDS_MeshElement* add_BAR_3(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddEdgeWithID( ids[0], ids[1], ids[2], ID ); + } + SMDS_MeshElement* add_TRI_3(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddFaceWithID( ids[0], ids[2], ids[1], ID ); + } + SMDS_MeshElement* add_TRI_6(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddFaceWithID( ids[0], ids[2], ids[1], ids[5], ids[4], ids[3], ID ); + } + SMDS_MeshElement* add_QUAD_4(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddFaceWithID( ids[0], ids[3], ids[2], ids[1], ID ); + } + SMDS_MeshElement* add_QUAD_8(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddFaceWithID( ids[0],ids[3],ids[2],ids[1],ids[7],ids[6],ids[5],ids[4], ID ); + } + SMDS_MeshElement* add_QUAD_9(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddFaceWithID( ids[0],ids[3],ids[2],ids[1],ids[7],ids[6],ids[5],ids[4],ids[8], ID); + } + SMDS_MeshElement* add_TETRA_4(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0], ids[2], ids[1], ids[3], ID ); + } + SMDS_MeshElement* add_TETRA_10(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[6], + ids[5],ids[4],ids[7],ids[9],ids[8], ID ); + } + SMDS_MeshElement* add_PYRA_5(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ID ); + } + SMDS_MeshElement* add_PYRA_13(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[8],ids[7], + ids[6],ids[5],ids[9],ids[12],ids[11],ids[10], ID ); + } + SMDS_MeshElement* add_PENTA_6(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[5],ids[4], ID ); + } + SMDS_MeshElement* add_PENTA_15(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[2],ids[1],ids[3],ids[5],ids[4],ids[8],ids[7], + ids[6],ids[9],ids[11],ids[10],ids[14],ids[13],ids[12], ID ); + } + SMDS_MeshElement* add_HEXA_8(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6],ids[5], ID ); + } + SMDS_MeshElement* add_HEXA_20(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6], + ids[5],ids[11],ids[10],ids[9],ids[8],ids[12],ids[15], + ids[14],ids[13],ids[19],ids[18],ids[17],ids[16], ID ); + } + SMDS_MeshElement* add_HEXA_27(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + return mesh->AddVolumeWithID( ids[0],ids[3],ids[2],ids[1],ids[4],ids[7],ids[6], + ids[5],ids[11],ids[10],ids[9],ids[8],ids[12],ids[15], + ids[14],ids[13],ids[19],ids[18],ids[17],ids[16], + ids[20],ids[24],ids[23],ids[22],ids[21],ids[25],ids[26], ID ); + } + SMDS_MeshElement* add_NGON(cgsize_t* ids, SMESHDS_Mesh* mesh, int ID) + { + vector idVec( ids[0] ); + for ( int i = 0; i < ids[0]; ++i ) + idVec[ i ] = (int) ids[ i + 1]; + return mesh->AddPolygonalFaceWithID( idVec, ID ); + } + + typedef SMDS_MeshElement* (* PAddElemFun) (cgsize_t* ids, SMESHDS_Mesh* mesh, int ID); + + //================================================================================ + /*! + * \brief Return an array of functions each adding an element of a particular type + */ + //================================================================================ + + PAddElemFun* getAddElemFunTable() + { + static vector< PAddElemFun > funVec; + if ( funVec.empty() ) + { + funVec.resize( NofValidElementTypes, (PAddElemFun)0 ); + funVec[ CGNS_ENUMV( NODE )] = add_0D ; + funVec[ CGNS_ENUMV( BAR_2 )] = add_BAR_2 ; + funVec[ CGNS_ENUMV( BAR_3 )] = add_BAR_3 ; + funVec[ CGNS_ENUMV( TRI_3 )] = add_TRI_3 ; + funVec[ CGNS_ENUMV( TRI_6 )] = add_TRI_6 ; + funVec[ CGNS_ENUMV( QUAD_4 )] = add_QUAD_4 ; + funVec[ CGNS_ENUMV( QUAD_8 )] = add_QUAD_8 ; + funVec[ CGNS_ENUMV( QUAD_9 )] = add_QUAD_9 ; + funVec[ CGNS_ENUMV( TETRA_4 )] = add_TETRA_4 ; + funVec[ CGNS_ENUMV( TETRA_10 )] = add_TETRA_10; + funVec[ CGNS_ENUMV( PYRA_5 )] = add_PYRA_5 ; + funVec[ CGNS_ENUMV( PYRA_13 )] = add_PYRA_13 ; + funVec[ CGNS_ENUMV( PYRA_14 )] = add_PYRA_13 ; + funVec[ CGNS_ENUMV( PENTA_6 )] = add_PENTA_6 ; + funVec[ CGNS_ENUMV( PENTA_15 )] = add_PENTA_15; + funVec[ CGNS_ENUMV( PENTA_18 )] = add_PENTA_15; + funVec[ CGNS_ENUMV( HEXA_8 )] = add_HEXA_8 ; + funVec[ CGNS_ENUMV( HEXA_20 )] = add_HEXA_20 ; + funVec[ CGNS_ENUMV( HEXA_27 )] = add_HEXA_27 ; + funVec[ CGNS_ENUMV( NGON_n )] = add_NGON ; + } + return &funVec[0]; + } + + //================================================================================ + /*! + * \brief Finds an existing boundary element + */ + //================================================================================ + + const SMDS_MeshElement* findElement(const cgsize_t* nodeIDs, + const int nbNodes, + const SMESHDS_Mesh* mesh) + { + const SMDS_MeshNode* nn[4]; // look for quad4 or seg2 + if (( nn[0] = mesh->FindNode( nodeIDs[0] ))) + { + SMDSAbs_ElementType eType = nbNodes==4 ? SMDSAbs_Face : SMDSAbs_Edge; + SMDS_ElemIteratorPtr eIt = nn[0]->GetInverseElementIterator( eType ); + if ( eIt->more() ) + for ( int i = 1; i < nbNodes; ++i ) + nn[i] = mesh->FindNode( nodeIDs[i] ); + while ( eIt->more() ) + { + const SMDS_MeshElement* e = eIt->next(); + if ( e->NbNodes() == nbNodes ) + { + bool elemOK = true; + for ( int i = 1; i < nbNodes && elemOK; ++i ) + elemOK = ( e->GetNodeIndex( nn[i] ) >= 0 ); + if ( elemOK ) + return e; + } + } + } + return 0; + } + +} // namespace + +//================================================================================ +/*! + * \brief Perform reading a myMeshId-th mesh + */ +//================================================================================ + +Driver_Mesh::Status DriverCGNS_Read::Perform() +{ + myErrorMessages.clear(); + + Status aResult; + if (( aResult = open() ) != DRS_OK ) + return aResult; + + // read nb of meshes (CGNSBase_t) + if ( myMeshId < 0 || myMeshId >= GetNbMeshes(aResult)) + return addMessage( SMESH_Comment("Invalid mesh index :") << myMeshId ); + + // read a name and a dimension of the mesh + const int cgnsBase = myMeshId + 1; + char meshName[CGNS_NAME_SIZE]; + int meshDim, spaceDim; + if ( cg_base_read( _fn, cgnsBase, meshName, &meshDim, &spaceDim) != CG_OK ) + return addMessage( cg_get_error() ); + + if ( spaceDim < 1 || spaceDim > 3 ) + return addMessage( SMESH_Comment("Invalid space dimension: ") << spaceDim + << " in mesh '" << meshName << "'"); + + myMeshName = meshName; + + // read nb of domains (Zone_t) in the mesh + int nbZones = 0; + if ( cg_nzones (_fn, cgnsBase, &nbZones) != CG_OK ) + return addMessage( cg_get_error() ); + + if ( nbZones < 1 ) + return addMessage( SMESH_Comment("Empty mesh: '") << meshName << "'"); + + // read the domains (zones) + // ------------------------ + map< string, TZoneData > zonesByName; + char name[CGNS_NAME_SIZE]; + cgsize_t sizes[NB_ZONE_SIZE_VAL]; + memset(sizes, 0, NB_ZONE_SIZE_VAL * sizeof(cgsize_t)); + + const SMDS_MeshInfo& meshInfo = myMesh->GetMeshInfo(); + int groupID = myMesh->GetGroups().size(); + + for ( int iZone = 1; iZone <= nbZones; ++iZone ) + { + // size and name of a zone + if ( cg_zone_read( _fn, cgnsBase, iZone, name, sizes) != CG_OK) { + addMessage( cg_get_error() ); + continue; + } + TZoneData& zone = zonesByName[ name ]; + zone._id = iZone; + zone._nodeIdShift = meshInfo.NbNodes(); + zone._elemIdShift = meshInfo.NbElements(); + zone.SetSizeAndDim( sizes, meshDim ); + + // mesh type of the zone + if ( cg_zone_type ( _fn, cgnsBase, iZone, &zone._type) != CG_OK) { + addMessage( cg_get_error() ); + continue; + } + + switch ( zone._type ) + { + case CGNS_ENUMV( Unstructured ): + case CGNS_ENUMV( Structured ): + break; + case CGNS_ENUMV( ZoneTypeNull ): + addMessage( "Meshes with ZoneTypeNull are not supported"); + continue; + case CGNS_ENUMV( ZoneTypeUserDefined ): + addMessage( "Meshes with ZoneTypeUserDefined are not supported"); + continue; + default: + addMessage( "Unknown ZoneType_t"); + continue; + } + + // ----------- + // Read nodes + // ----------- + + if ( cg_ncoords( _fn, cgnsBase, iZone, &spaceDim) != CG_OK ) { + addMessage( cg_get_error() ); + continue; + } + if ( spaceDim < 1 ) { + addMessage( SMESH_Comment("No coordinates defined in zone ") + << iZone << " of Mesh " << myMeshId ); + continue; + } + // read coordinates + + cgsize_t rmin[3] = {1,1,1}; // range of nodes to read + cgsize_t rmax[3] = {1,1,1}; + int nbNodes = rmax[0] = zone._sizes[0]; + if ( zone.IsStructured()) + for ( int i = 1; i < meshDim; ++i ) + nbNodes *= rmax[i] = zone._sizes[i]; + + vector coords[3]; + for ( int c = 1; c <= spaceDim; ++c) + { + coords[c-1].resize( nbNodes ); + + CGNS_ENUMV( DataType_t ) type; + if ( cg_coord_info( _fn, cgnsBase, iZone, c, &type, name) != CG_OK || + cg_coord_read( _fn, cgnsBase, iZone, name, CGNS_ENUMV(RealDouble), + rmin, rmax, (void*)&(coords[c-1][0])) != CG_OK) + { + addMessage( cg_get_error() ); + coords[c-1].clear(); + break; + } + } + if ( coords[ spaceDim-1 ].empty() ) + continue; // there was an error while reading coordinates + + // fill coords with zero if spaceDim < 3 + for ( int c = 2; c <= 3; ++c) + if ( coords[ c-1 ].empty() ) + coords[ c-1 ].resize( nbNodes, 0.0 ); + + // create nodes + try { + for ( int i = 0; i < nbNodes; ++i ) + myMesh->AddNodeWithID( coords[0][i], coords[1][i], coords[2][i], i+1+zone._nodeIdShift ); + } + catch ( std::exception& exc ) // expect std::bad_alloc + { + addMessage( exc.what() ); + break; + } + + // Read connectivity between zones. Nodes of the zone interface will be + // replaced within the zones read later + string err = zone.ReadZonesConnection( _fn, cgnsBase, zonesByName, myMesh ); + if ( !err.empty() ) + addMessage( err ); + + // -------------- + // Read elements + // -------------- + if ( zone.IsStructured()) + { + int nbI = zone._sizeX - 1, nbJ = zone._sizeY - 1, nbK = zone._sizeZ - 1; + cgsize_t nID[8]; + if ( meshDim > 2 && nbK > 0 ) + { + for ( int k = 1; k <= nbK; ++k ) + for ( int j = 1; j <= nbJ; ++j ) + for ( int i = 1; i <= nbI; ++i ) + { + zone.CellNodes( i, j, k, nID ); + zone.ReplaceNodes( nID, 8 ); + myMesh->AddVolumeWithID(nID[0],nID[1],nID[2],nID[3],nID[4],nID[5],nID[6],nID[7], + meshInfo.NbElements()+1); + } + } + else if ( meshDim > 1 && nbJ > 0 ) + { + for ( int j = 1; j <= nbJ; ++j ) + for ( int i = 1; i <= nbI; ++i ) + { + zone.CellNodes( i, j, nID ); + zone.ReplaceNodes( nID, 4 ); + myMesh->AddFaceWithID(nID[0],nID[1],nID[2],nID[3], meshInfo.NbElements()+1); + } + } + else if ( meshDim > 0 && nbI > 0 ) + { + nID[0] = zone.NodeID( 1, 0, 0 ); + for ( int i = 1; i <= nbI; ++i, ++nID[0] ) + { + nID[1] = nID[0]+1; + zone.ReplaceNodes( nID, 2 ); + myMesh->AddEdgeWithID(nID[0],nID[1], meshInfo.NbElements()+1); + } + } + } + else + { + // elements can be stored in different sections each dedicated to one element type + int nbSections = 0; + if ( cg_nsections( _fn, cgnsBase, iZone, &nbSections) != CG_OK) + { + addMessage( cg_get_error() ); + continue; + } + PAddElemFun* addElemFuns = getAddElemFunTable(), curAddElemFun = 0; + int nbNotSuppElem = 0; // nb elements of not supported types + bool polyhedError = false; // error at polyhedron creation + + // read element data + + CGNS_ENUMT( ElementType_t ) elemType; + cgsize_t start, end; // range of ids of elements of a zone + cgsize_t eDataSize = 0; + int nbBnd, parent_flag; + for ( int iSec = 1; iSec <= nbSections; ++iSec ) + { + if ( cg_section_read( _fn, cgnsBase, iZone, iSec, name, &elemType, + &start, &end, &nbBnd, &parent_flag) != CG_OK || + cg_ElementDataSize( _fn, cgnsBase, iZone, iSec, &eDataSize ) != CG_OK ) + { + addMessage( cg_get_error() ); + continue; + } + vector< cgsize_t > elemData( eDataSize ); + if ( cg_elements_read( _fn, cgnsBase, iZone, iSec, &elemData[0], NULL ) != CG_OK ) + { + addMessage( cg_get_error() ); + continue; + } + // store elements + + int pos = 0, cgnsNbNodes = 0, elemID = start + zone._elemIdShift; + cg_npe( elemType, &cgnsNbNodes ); // get nb nodes by element type + curAddElemFun = addElemFuns[ elemType ]; + SMDS_MeshElement* newElem = 0; + const SMDS_MeshElement* face; + + while ( pos < eDataSize ) + { + CGNS_ENUMT( ElementType_t ) currentType = elemType; + if ( currentType == CGNS_ENUMV( MIXED )) { + //ElementConnectivity = Etype1, Node11, Node21, ... NodeN1, + // Etype2, Node12, Node22, ... NodeN2, + // ... + // EtypeM, Node1M, Node2M, ... NodeNM + currentType = (CGNS_ENUMT(ElementType_t)) elemData[ pos++ ]; + cg_npe( currentType, &cgnsNbNodes ); + curAddElemFun = addElemFuns[ currentType ]; + } + if ( cgnsNbNodes < 1 ) // poly elements + { + if ( currentType == CGNS_ENUMV( NFACE_n )) // polyhedron + { + //ElementConnectivity = Nfaces1, Face11, Face21, ... FaceN1, + // Nfaces2, Face12, Face22, ... FaceN2, + // ... + // NfacesM, Face1M, Face2M, ... FaceNM + const int nbFaces = elemData[ pos++ ]; + vector quantities( nbFaces ); + vector nodes, faceNodes; + nodes.reserve( nbFaces * 4 ); + for ( int iF = 0; iF < nbFaces; ++iF ) + { + const int faceID = std::abs( elemData[ pos++ ]) + zone._elemIdShift; + if (( face = myMesh->FindElement( faceID )) && face->GetType() == SMDSAbs_Face ) + { + const bool reverse = ( elemData[ pos-1 ] < 0 ); + const int iQuad = face->IsQuadratic() ? 1 : 0; + SMDS_ElemIteratorPtr nIter = face->interlacedNodesElemIterator(); + faceNodes.assign( SMDS_MeshElement::iterator( nIter ), + SMDS_MeshElement::iterator()); + if ( iQuad && reverse ) + nodes.push_back( faceNodes[0] ); + if ( reverse ) + nodes.insert( nodes.end(), faceNodes.rbegin(), faceNodes.rend() - iQuad ); + else + nodes.insert( nodes.end(), faceNodes.begin(), faceNodes.end() ); + + quantities[ iF ] = face->NbNodes(); + } + else { + polyhedError = true; + break; + } + } + if ( quantities.back() ) + { + myMesh->AddPolyhedralVolumeWithID( nodes, quantities, elemID ); + } + } + else if ( currentType == CGNS_ENUMV( NGON_n )) // polygon + { + // ElementConnectivity = Nnodes1, Node11, Node21, ... NodeN1, + // Nnodes2, Node12, Node22, ... NodeN2, + // ... + // NnodesM, Node1M, Node2M, ... NodeNM + const int nbNodes = elemData[ pos ]; + zone.ReplaceNodes( &elemData[pos+1], nbNodes, zone._nodeIdShift ); + newElem = add_NGON( &elemData[pos ], myMesh, elemID ); + pos += nbNodes + 1; + } + } + else // standard elements + { + zone.ReplaceNodes( &elemData[pos], cgnsNbNodes, zone._nodeIdShift ); + newElem = curAddElemFun( &elemData[pos], myMesh, elemID ); + pos += cgnsNbNodes; + nbNotSuppElem += int( newElem && newElem->NbNodes() != cgnsNbNodes ); + } + elemID++; + + } // loop on elemData + } // loop on cgns sections + + if ( nbNotSuppElem > 0 ) + addMessage( SMESH_Comment(nbNotSuppElem) << " elements of not supported types" + << " have beem converted to close types"); + if ( polyhedError ) + addMessage( "Some polyhedral elements have been skipped due to internal(?) errors" ); + + } // reading unstructured elements + + zone._nbNodes = meshInfo.NbNodes() - zone._nodeIdShift; + zone._nbElems = meshInfo.NbElements() - zone._elemIdShift; + + // ------------------------------------------- + // Read Boundary Conditions into SMESH groups + // ------------------------------------------- + int nbBC = 0; + if ( cg_nbocos( _fn, cgnsBase, iZone, &nbBC) == CG_OK ) + { + CGNS_ENUMT( BCType_t ) bcType; + CGNS_ENUMT( PointSetType_t ) psType; + CGNS_ENUMT( DataType_t ) normDataType; + cgsize_t nbPnt, normFlag; + int normIndex[3], nbDS; + for ( int iBC = 1; iBC <= nbBC; ++iBC ) + { + if ( cg_boco_info( _fn, cgnsBase, iZone, iBC, name, &bcType, &psType, + &nbPnt, normIndex, &normFlag, &normDataType, &nbDS ) != CG_OK ) + { + addMessage( cg_get_error() ); + continue; + } + vector< cgsize_t > ids( nbPnt * zone.IndexSize() ); + CGNS_ENUMT( GridLocation_t ) location; + if ( cg_boco_read( _fn, cgnsBase, iZone, iBC, &ids[0], NULL ) != CG_OK || + cg_boco_gridlocation_read( _fn, cgnsBase, iZone, iBC, &location) != CG_OK ) + { + addMessage( cg_get_error() ); + continue; + } + SMDSAbs_ElementType elemType = SMDSAbs_All; + switch ( location ) { + case CGNS_ENUMV( Vertex ): elemType = SMDSAbs_Node; break; + case CGNS_ENUMV( FaceCenter ): elemType = SMDSAbs_Face; break; + case CGNS_ENUMV( IFaceCenter ): elemType = SMDSAbs_Face; break; + case CGNS_ENUMV( JFaceCenter ): elemType = SMDSAbs_Face; break; + case CGNS_ENUMV( KFaceCenter ): elemType = SMDSAbs_Face; break; + case CGNS_ENUMV( EdgeCenter ): elemType = SMDSAbs_Edge; break; + default:; + } + SMESHDS_Group* group = new SMESHDS_Group ( groupID++, myMesh, elemType ); + myMesh->AddGroup( group ); + SMESH_Comment groupName( name ); groupName << " " << cg_BCTypeName( bcType ); + group->SetStoreName( groupName.c_str() ); + SMDS_MeshGroup& groupDS = group->SMDSGroup(); + + if ( elemType == SMDSAbs_Node ) + { + if ( zone.IsStructured() ) + { + vector< cgsize_t > nodeIds; + if ( psType == CGNS_ENUMV( PointRange )) + { + // nodes are given as (ijkMin, ijkMax) + TPointRangeIterator idIt( & ids[0], meshDim ); + nodeIds.reserve( idIt.Size() ); + while ( idIt.More() ) + nodeIds.push_back( zone.NodeID( idIt.Next() )); + } + else + { + // nodes are given as (ijk1, ijk2, ..., ijkN) + nodeIds.reserve( ids.size() / meshDim ); + for ( size_t i = 0; i < ids.size(); i += meshDim ) + nodeIds.push_back( zone.NodeID( ids[i], ids[i+1], ids[i+2] )); + } + ids.swap( nodeIds ); + } + else if ( zone._nodeIdShift ) + { + for ( size_t i = 0; i < ids.size(); ++i ) + ids[i] += zone._nodeIdShift; + } + zone.ReplaceNodes( &ids[0], ids.size() ); + + for ( size_t i = 0; i < ids.size(); ++i ) + if ( const SMDS_MeshNode* n = myMesh->FindNode( ids[i] )) + groupDS.Add( n ); + } + else // BC applied to elements + { + if ( zone.IsStructured() ) + { + int axis = 0; // axis perpendiculaire to which boundary elements are oriented + if ( (int) ids.size() >= meshDim * 2 ) + { + for ( ; axis < meshDim; ++axis ) + if ( ids[axis] - ids[axis+meshDim] == 0 ) + break; + } + else + { + for ( ; axis < meshDim; ++axis ) + if ( normIndex[axis] != 0 ) + break; + } + if ( axis == meshDim ) + { + addMessage( SMESH_Comment("Invalid NormalIndex in BC ") << name ); + continue; + } + const int nbElemNodesByDim[] = { 1, 2, 4, 8 }; + const int nbElemNodes = nbElemNodesByDim[ meshDim ]; + + if ( psType == CGNS_ENUMV( PointRange ) || + psType == CGNS_ENUMV( ElementRange )) + { + // elements are given as (ijkMin, ijkMax) + typedef void (TZoneData::*PGetNodesFun)( const gp_XYZ& ijk, cgsize_t* ids ) const; + PGetNodesFun getNodesFun = 0; + if ( elemType == SMDSAbs_Face && meshDim == 3 ) + switch ( axis ) { + case 0: getNodesFun = & TZoneData::IFaceNodes; + case 1: getNodesFun = & TZoneData::JFaceNodes; + case 2: getNodesFun = & TZoneData::KFaceNodes; + } + else if ( elemType == SMDSAbs_Edge && meshDim == 2 ) + switch ( axis ) { + case 0: getNodesFun = & TZoneData::IEdgeNodes; + case 1: getNodesFun = & TZoneData::JEdgeNodes; + } + if ( !getNodesFun ) + { + addMessage( SMESH_Comment("Unsupported BC location in BC ") << name + << " " << cg_GridLocationName( location ) + << " in " << meshDim << " mesh"); + continue; + } + TPointRangeIterator rangeIt( & ids[0], meshDim ); + vector< cgsize_t > elemNodeIds( rangeIt.Size() * nbElemNodes ); + for ( int i = 0; rangeIt.More(); i+= nbElemNodes ) + (zone.*getNodesFun)( rangeIt.Next(), &elemNodeIds[i] ); + + ids.swap( elemNodeIds ); + } + else + { + // elements are given as (ijk1, ijk2, ..., ijkN) + typedef void (TZoneData::*PGetNodesFun)( int i, int j, int k, cgsize_t* ids ) const; + PGetNodesFun getNodesFun = 0; + if ( elemType == SMDSAbs_Face ) + switch ( axis ) { + case 0: getNodesFun = & TZoneData::IFaceNodes; + case 1: getNodesFun = & TZoneData::JFaceNodes; + case 2: getNodesFun = & TZoneData::KFaceNodes; + } + else if ( elemType == SMDSAbs_Edge && meshDim == 2 ) + switch ( axis ) { + case 0: getNodesFun = & TZoneData::IEdgeNodes; + case 1: getNodesFun = & TZoneData::JEdgeNodes; + } + if ( !getNodesFun ) + { + addMessage( SMESH_Comment("Unsupported BC location in BC ") << name + << " " << cg_GridLocationName( location ) + << " in " << meshDim << " mesh"); + continue; + } + vector< cgsize_t > elemNodeIds( ids.size()/meshDim * nbElemNodes ); + for ( size_t i = 0, j = 0; i < ids.size(); i += meshDim, j += nbElemNodes ) + (zone.*getNodesFun)( ids[i], ids[i+1], ids[i+2], &elemNodeIds[j] ); + + ids.swap( elemNodeIds ); + } + zone.ReplaceNodes( &ids[0], ids.size() ); + + PAddElemFun addElemFun = 0; + switch ( meshDim ) { + case 1: addElemFun = & add_BAR_2; + case 2: addElemFun = & add_QUAD_4; + case 3: addElemFun = & add_HEXA_8; + } + int elemID = meshInfo.NbElements(); + const SMDS_MeshElement* elem = 0; + for ( size_t i = 0; i < ids.size(); i += nbElemNodes ) + { + if ( iZone == 1 || !( elem = findElement( &ids[i], nbElemNodes, myMesh ))) + elem = addElemFun( &ids[i], myMesh, ++elemID ); + groupDS.Add( elem ); + } + } + else // unstructured zone + { + if ( zone._elemIdShift ) + for ( size_t i = 0; i < ids.size(); ++i ) + ids[i] += zone._elemIdShift; + + if ( psType == CGNS_ENUMV( PointRange ) && ids.size() == 2 ) + { + for ( cgsize_t i = ids[0]; i <= ids[1]; ++i ) + if ( const SMDS_MeshElement* e = myMesh->FindElement( i )) + groupDS.Add( e ); + } + else + { + for ( size_t i = 0; i < ids.size(); ++i ) + if ( const SMDS_MeshElement* e = myMesh->FindElement( ids[i] )) + groupDS.Add( e ); + } + } + } // end "BC applied to elements" + + // to have group type according to a real elem type + group->SetType( groupDS.GetType() ); + + } // loop on BCs of the zone + } + else + { + addMessage( cg_get_error() ); + } + } // loop on the zones of a mesh + + + // ------------------------------------------------------------------------ + // Make groups for multiple zones and remove free nodes at zone interfaces + // ------------------------------------------------------------------------ + map< string, TZoneData >::iterator nameZoneIt = zonesByName.begin(); + for ( ; nameZoneIt != zonesByName.end(); ++nameZoneIt ) + { + TZoneData& zone = nameZoneIt->second; + if ( zone._nbElems == 0 ) continue; + if ( zone._nbElems == meshInfo.NbElements() ) break; // there is only one non-empty zone + + // make a group + SMDSAbs_ElementType elemType = myMesh->GetElementType( zone._elemIdShift + 1, + /*iselem=*/true ); + SMESHDS_Group* group = new SMESHDS_Group ( groupID++, myMesh, elemType ); + myMesh->AddGroup( group ); + group->SetStoreName( nameZoneIt->first.c_str() ); + SMDS_MeshGroup& groupDS = group->SMDSGroup(); + + for ( int i = 1; i <= zone._nbElems; ++i ) + if ( const SMDS_MeshElement* e = myMesh->FindElement( i + zone._elemIdShift )) + groupDS.Add( e ); + + // remove free nodes + map< int, int >::iterator nnRmKeepIt = zone._nodeReplacementMap.begin(); + for ( ; nnRmKeepIt != zone._nodeReplacementMap.end(); ++nnRmKeepIt ) + if ( const SMDS_MeshNode* n = myMesh->FindNode( nnRmKeepIt->first )) + if ( n->NbInverseElements() == 0 ) + myMesh->RemoveFreeNode( n, (SMESHDS_SubMesh *)0, /*fromGroups=*/false ); + } + + aResult = myErrorMessages.empty() ? DRS_OK : DRS_WARN_SKIP_ELEM; + + return aResult; +} + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +DriverCGNS_Read::DriverCGNS_Read() +{ + _fn = -1; +} +//================================================================================ +/*! + * \brief Close the cgns file at destruction + */ +//================================================================================ + +DriverCGNS_Read::~DriverCGNS_Read() +{ + if ( _fn > 0 ) + cg_close( _fn ); +} + +//================================================================================ +/*! + * \brief Opens myFile + */ +//================================================================================ + +Driver_Mesh::Status DriverCGNS_Read::open() +{ + if ( _fn < 0 ) + { + +#ifdef CG_MODE_READ + int res = cg_open(myFile.c_str(), CG_MODE_READ, &_fn); +#else + int res = cg_open(myFile.c_str(), MODE_READ, &_fn); +#endif + if ( res != CG_OK) + { + addMessage( cg_get_error(), /*fatal = */true ); + } + } + return _fn >= 0 ? DRS_OK : DRS_FAIL; +} + +//================================================================================ +/*! + * \brief Reads nb of meshes in myFile + */ +//================================================================================ + +int DriverCGNS_Read::GetNbMeshes(Status& theStatus) +{ + if (( theStatus = open()) != DRS_OK ) + return 0; + + int nbases = 0; + if(cg_nbases( _fn, &nbases) != CG_OK) + theStatus = addMessage( cg_get_error(), /*fatal = */true ); + + return nbases; +} diff --git a/src/DriverCGNS/DriverCGNS_Write.cxx b/src/DriverCGNS/DriverCGNS_Write.cxx new file mode 100644 index 0000000..844bb86 --- /dev/null +++ b/src/DriverCGNS/DriverCGNS_Write.cxx @@ -0,0 +1,606 @@ +// Copyright (C) 2007-2016 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 : DriverCGNS_Write.cxx +// Created : Fri Aug 5 17:43:54 2011 +// Author : Edward AGAPOV (eap) + +#include "DriverCGNS_Write.hxx" + +#include "SMDS_MeshNode.hxx" +#include "SMDS_VolumeTool.hxx" +#include "SMESHDS_GroupBase.hxx" +#include "SMESHDS_Mesh.hxx" +#include "SMESH_Comment.hxx" + +#include +#include + +#if CGNS_VERSION < 3100 +# define cgsize_t int +#endif + +using namespace std; + +namespace +{ + //================================================================================ + /*! + * \brief Return interlace and type of CGNS element for the given SMDSAbs_EntityType + */ + //================================================================================ + + const int* getInterlaceAndType( const SMDSAbs_EntityType smType, + CGNS_ENUMT( ElementType_t ) & cgType ) + { + static vector< const int* > interlaces; + static vector< CGNS_ENUMT( ElementType_t )> cgTypes; + if ( interlaces.empty() ) + { + interlaces.resize( SMDSEntity_Last, 0 ); + cgTypes.resize( SMDSEntity_Last, CGNS_ENUMV( ElementTypeNull )); + { + static int ids[] = {0}; + interlaces[SMDSEntity_0D] = ids; + cgTypes [SMDSEntity_0D] = CGNS_ENUMV( NODE ); + } + { + static int ids[] = { 0, 1 }; + interlaces[SMDSEntity_Edge] = ids; + cgTypes [SMDSEntity_Edge] = CGNS_ENUMV( BAR_2 ); + } + { + static int ids[] = { 0, 1, 2 }; + interlaces[SMDSEntity_Quad_Edge] = ids; + cgTypes [SMDSEntity_Quad_Edge] = CGNS_ENUMV( BAR_3 ); + } + { + static int ids[] = { 0, 2, 1 }; + interlaces[SMDSEntity_Triangle] = ids; + cgTypes [SMDSEntity_Triangle] = CGNS_ENUMV( TRI_3 ); + } + { + static int ids[] = { 0, 2, 1, 5, 4, 3 }; + interlaces[SMDSEntity_Quad_Triangle] = ids; + cgTypes [SMDSEntity_Quad_Triangle] = CGNS_ENUMV( TRI_6 ); + interlaces[SMDSEntity_BiQuad_Triangle] = ids; + cgTypes [SMDSEntity_BiQuad_Triangle] = CGNS_ENUMV( TRI_6 ); + } + { + static int ids[] = { 0, 3, 2, 1 }; + interlaces[SMDSEntity_Quadrangle] = ids; + cgTypes [SMDSEntity_Quadrangle] = CGNS_ENUMV( QUAD_4 ); + } + { + static int ids[] = { 0,3,2,1,7,6,5,4 }; + interlaces[SMDSEntity_Quad_Quadrangle] = ids; + cgTypes [SMDSEntity_Quad_Quadrangle] = CGNS_ENUMV( QUAD_8 ); + } + { + static int ids[] = { 0,3,2,1,7,6,5,4,8 }; + interlaces[SMDSEntity_BiQuad_Quadrangle] = ids; + cgTypes [SMDSEntity_BiQuad_Quadrangle] = CGNS_ENUMV( QUAD_9 ); + } + { + static int ids[] = { 0, 2, 1, 3 }; + interlaces[SMDSEntity_Tetra] = ids; + cgTypes [SMDSEntity_Tetra] = CGNS_ENUMV( TETRA_4 ); + } + { + static int ids[] = { 0,2,1,3,6,5,4,7,9,8 }; + interlaces[SMDSEntity_Quad_Tetra] = ids; + cgTypes [SMDSEntity_Quad_Tetra] = CGNS_ENUMV( TETRA_10 ); + } + { + static int ids[] = { 0,3,2,1,4 }; + interlaces[SMDSEntity_Pyramid] = ids; + cgTypes [SMDSEntity_Pyramid] = CGNS_ENUMV( PYRA_5 ); + } + { + static int ids[] = { 0,3,2,1,4,8,7,6,5,9,12,11,10 }; + interlaces[SMDSEntity_Quad_Pyramid] = ids; + cgTypes [SMDSEntity_Quad_Pyramid] = CGNS_ENUMV( PYRA_13 ); + } + { + static int ids[] = { 0,2,1,3,5,4 }; + interlaces[SMDSEntity_Penta] = ids; + cgTypes [SMDSEntity_Penta] = CGNS_ENUMV( PENTA_6 ); + } + { + static int ids[] = { 0,2,1,3,5,4,8,7,6,9,11,10,14,13,12 }; + interlaces[SMDSEntity_Quad_Penta] = ids; + cgTypes [SMDSEntity_Quad_Penta] = CGNS_ENUMV( PENTA_15 ); + } + { + static int ids[] = { 0,3,2,1,4,7,6,5 }; + interlaces[SMDSEntity_Hexa] = ids; + cgTypes [SMDSEntity_Hexa] = CGNS_ENUMV( HEXA_8 ); + } + { + static int ids[] = { 0,3,2,1,4,7,6,5,11,10,9,8,12,15,14,13,19,18,17,16 }; + interlaces[SMDSEntity_Quad_Hexa] = ids; + cgTypes [SMDSEntity_Quad_Hexa] = CGNS_ENUMV( HEXA_20 ); + } + { + static int ids[] = { 0,3,2,1,4,7,6,5,11,10,9,8,12,15,14,13,19,18,17,16, + 20, 24,23,22,21, 25, 26}; + interlaces[SMDSEntity_TriQuad_Hexa] = ids; + cgTypes [SMDSEntity_TriQuad_Hexa] = CGNS_ENUMV( HEXA_27 ); + } + { + cgTypes[SMDSEntity_Polygon] = CGNS_ENUMV( NGON_n ); + cgTypes[SMDSEntity_Quad_Polygon] = CGNS_ENUMV( NGON_n ); + cgTypes[SMDSEntity_Polyhedra] = CGNS_ENUMV( NFACE_n ); + cgTypes[SMDSEntity_Hexagonal_Prism] = CGNS_ENUMV( NFACE_n ); + } + } + cgType = cgTypes[ smType ]; + return interlaces[ smType ]; + } + + //================================================================================ + /*! + * \brief Cut off type of boundary condition from the group name + */ + //================================================================================ + + CGNS_ENUMT( BCType_t ) getBCType( string& groupName ) + { + CGNS_ENUMT( BCType_t ) bcType = CGNS_ENUMV( BCGeneral ); // default type + + // boundary condition type starts from "BC" + size_t bcBeg = groupName.find("BC"); + if ( bcBeg != string::npos ) + { + for ( int t = 0; t < NofValidBCTypes; ++t ) + { + CGNS_ENUMT( BCType_t ) type = CGNS_ENUMT( BCType_t )( t ); + string typeName = cg_BCTypeName( type ); + if ( typeName == &groupName[0] + bcBeg ) + { + bcType = type; + while ( bcBeg > 0 && isspace( bcBeg-1 )) + --bcBeg; + if ( bcBeg == 0 ) + groupName = "Group"; + else + groupName = groupName.substr( 0, bcBeg-1 ); + } + } + } + return bcType; + } + + //================================================================================ + /*! + * \brief Sortable face of a polyhedron + */ + struct TPolyhedFace + { + int _id; // id of NGON_n + vector< int > _nodes; // lowest node IDs used for sorting + + TPolyhedFace( const SMDS_MeshNode** nodes, const int nbNodes, int ID):_id(ID) + { + set< int > ids; + for ( int i = 0; i < nbNodes; ++i ) + ids.insert( nodes[i]->GetID() ); + + _nodes.resize( 3 ); // std::min( nbNodes, 4 )); hope 3 nodes is enough + set< int >::iterator idIt = ids.begin(); + for ( size_t j = 0; j < _nodes.size(); ++j, ++idIt ) + _nodes[j] = *idIt; + } + bool operator< (const TPolyhedFace& o ) const + { + return _nodes < o._nodes; + } + }; + //================================================================================ + /*! + * \brief Return CGNS id of an element + */ + //================================================================================ + + cgsize_t cgnsID( const SMDS_MeshElement* elem, + const map< const SMDS_MeshElement*, cgsize_t >& elem2cgID ) + { + map< const SMDS_MeshElement*, cgsize_t >::const_iterator e2id = elem2cgID.find( elem ); + return ( e2id == elem2cgID.end() ? elem->GetID() : e2id->second ); + } + +} // namespace + +//================================================================================ +/*! + * \brief Write the mesh into the CGNS file + */ +//================================================================================ + +Driver_Mesh::Status DriverCGNS_Write::Perform() +{ + myErrorMessages.clear(); + + if ( !myMesh || myMesh->GetMeshInfo().NbElements() < 1 ) + return addMessage( !myMesh ? "NULL mesh" : "Empty mesh (no elements)", /*fatal = */true ); + + // open the file + if ( cg_open(myFile.c_str(), CG_MODE_MODIFY, &_fn) != CG_OK && + cg_open(myFile.c_str(), CG_MODE_WRITE, &_fn) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + + // create a Base + // -------------- + + const int spaceDim = 3; + int meshDim = 1; + if ( myMesh->NbFaces() > 0 ) meshDim = 2; + if ( myMesh->NbVolumes() > 0 ) meshDim = 3; + + if ( myMeshName.empty() ) + { + int nbases = 0; + if ( cg_nbases( _fn, &nbases) == CG_OK ) + myMeshName = ( SMESH_Comment("Base_") << nbases+1 ); + else + myMeshName = "Base_0"; + } + int iBase; + if ( cg_base_write( _fn, myMeshName.c_str(), meshDim, spaceDim, &iBase )) + return addMessage( cg_get_error(), /*fatal = */true ); + + // create a Zone + // -------------- + + int nbCells = myMesh->NbEdges(); + if ( meshDim == 3 ) + nbCells = myMesh->NbVolumes(); + else if ( meshDim == 2 ) + nbCells = myMesh->NbFaces(); + + cgsize_t size[9] = { myMesh->NbNodes(), nbCells, /*NBoundVertex=*/0, 0,0,0,0,0,0 }; + int iZone; + if ( cg_zone_write( _fn, iBase, "SMESH_Mesh", size, + CGNS_ENUMV( Unstructured ), &iZone) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + + // Map to store only elements whose an SMDS ID differs from a CGNS one + typedef map< const SMDS_MeshElement*, cgsize_t > TElem2cgIDMap; + vector< TElem2cgIDMap > elem2cgIDByEntity( SMDSEntity_Last ); + TElem2cgIDMap::iterator elem2cgIDIter; + + TElem2cgIDMap & n2cgID = elem2cgIDByEntity[ SMDSEntity_Node ]; + + // Write nodes + // ------------ + { + vector< double > coords( myMesh->NbNodes() ); + int iC; + // X + SMDS_NodeIteratorPtr nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true ); + for ( int i = 0; nIt->more(); ++i ) coords[i] = nIt->next()->X(); + if ( cg_coord_write( _fn, iBase, iZone, CGNS_ENUMV(RealDouble), + "CoordinateX", &coords[0], &iC) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + // Y + nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true ); + for ( int i = 0; nIt->more(); ++i ) coords[i] = nIt->next()->Y(); + if ( cg_coord_write( _fn, iBase, iZone, CGNS_ENUMV(RealDouble), + "CoordinateY", &coords[0], &iC) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + // Z + nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true ); + for ( int i = 0; nIt->more(); ++i ) coords[i] = nIt->next()->Z(); + if ( cg_coord_write( _fn, iBase, iZone, CGNS_ENUMV(RealDouble), + "CoordinateZ", &coords[0], &iC) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + + // store CGNS ids of nodes + nIt = myMesh->nodesIterator( /*idInceasingOrder=*/true ); + for ( int i = 0; nIt->more(); ++i ) + { + const SMDS_MeshElement* n = nIt->next(); + if ( n->GetID() != i+1 ) + n2cgID.insert( n2cgID.end(), make_pair( n, i+1 )); + } + } + // Write elements + // --------------- + + cgsize_t cgID = 1, startID; + + // write into a section all successive elements of one geom type + int iSec; + vector< cgsize_t > elemData; + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(); + const SMDS_MeshElement* elem = elemIt->next(); + while ( elem ) + { + const SMDSAbs_EntityType elemType = elem->GetEntityType(); + CGNS_ENUMT( ElementType_t ) cgType; + const int* interlace = getInterlaceAndType( elemType, cgType ); + + TElem2cgIDMap & elem2cgID = elem2cgIDByEntity[ elemType ]; + + elemData.clear(); + startID = cgID; + + if ( interlace ) // STANDARD elements + { + int cgnsNbNodes; // get nb nodes by element type, that can be less that elem->NbNodes() + cg_npe( cgType, &cgnsNbNodes ); + do + { + for ( int i = 0; i < cgnsNbNodes; ++i ) + elemData.push_back( cgnsID( elem->GetNode( interlace[i] ), n2cgID )); + if ( elem->GetID() != cgID ) + elem2cgID.insert( elem2cgID.end(), make_pair( elem, cgID )); + ++cgID; + elem = elemIt->more() ? elemIt->next() : 0; + } + while ( elem && elem->GetEntityType() == elemType ); + } + else if ( elemType == SMDSEntity_Polygon ) // POLYGONS + do + { + elemData.push_back( elem->NbNodes() ); + for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i ) + elemData.push_back( cgnsID( elem->GetNode(i), n2cgID )); + if ( elem->GetID() != cgID ) + elem2cgID.insert( elem2cgID.end(), make_pair( elem, cgID )); + ++cgID; + elem = elemIt->more() ? elemIt->next() : 0; + } + while ( elem && elem->GetEntityType() == elemType ); + + else if ( elemType == SMDSEntity_Quad_Polygon ) // QUADRATIC POLYGONS + do // write as linear NGON_n + { + elemData.push_back( elem->NbNodes() ); + interlace = & SMDS_MeshCell::interlacedSmdsOrder( SMDSEntity_Quad_Polygon, + elem->NbNodes() )[0]; + for ( int i = 0, nb = elem->NbNodes(); i < nb; ++i ) + elemData.push_back( cgnsID( elem->GetNode( interlace[i] ), n2cgID )); + if ( elem->GetID() != cgID ) + elem2cgID.insert( elem2cgID.end(), make_pair( elem, cgID )); + ++cgID; + elem = elemIt->more() ? elemIt->next() : 0; + } + while ( elem && elem->GetEntityType() == elemType ); + + else if ( elemType == SMDSEntity_Polyhedra || + elemType == SMDSEntity_Hexagonal_Prism) // POLYHEDRA + { + // to save polyhedrons after all + const SMDS_MeshInfo& meshInfo = myMesh->GetMeshInfo(); + if ( meshInfo.NbPolyhedrons() == meshInfo.NbElements() - cgID + 1 ) + break; // only polyhedrons remain + while ( elem && elem->GetEntityType() == elemType ) + elem = elemIt->more() ? elemIt->next() : 0; + continue; + } + + SMESH_Comment sectionName( cg_ElementTypeName( cgType )); + sectionName << " " << startID << " - " << cgID-1; + + if ( cg_section_write(_fn, iBase, iZone, sectionName.c_str(), cgType, startID, + cgID-1, /*nbndry=*/0, &elemData[0], &iSec) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + } + // Write polyhedral volumes + // ------------------------- + + if ( myMesh->GetMeshInfo().NbElements() > cgID-1 ) // polyhedra or hexagonal prisms remain + { + // the polyhedron (NFACE_n) is described as a set of signed face IDs, + // so first we are to write all polygones (NGON_n) bounding polyhedrons + + vector< cgsize_t > faceData; + set< TPolyhedFace > faces; + set< TPolyhedFace >::iterator faceInSet; + vector faceNodesVec; + int nbPolygones = 0, faceID; + + SMDS_VolumeTool vol; + + elemData.clear(); + + int nbPolyhTreated = 0; + + TElem2cgIDMap * elem2cgID = 0; + TElem2cgIDMap & n2cgID = elem2cgIDByEntity[ SMDSEntity_Node ]; + + SMDS_ElemIteratorPtr elemIt = myMesh->elementsIterator(); + while ( elemIt->more() ) + { + elem = elemIt->next(); + SMDSAbs_EntityType type = elem->GetEntityType(); + if ( type == SMDSEntity_Polyhedra || + type == SMDSEntity_Hexagonal_Prism ) + { + ++nbPolyhTreated; + vol.Set( elem ); + vol.SetExternalNormal(); + const int nbFaces = vol.NbFaces(); + elemData.push_back( nbFaces ); + for ( int iF = 0; iF < nbFaces; ++iF ) + { + const int nbNodes = vol.NbFaceNodes( iF ); + const SMDS_MeshNode** faceNodes = vol.GetFaceNodes( iF ); + faceNodesVec.assign( faceNodes, faceNodes + nbNodes ); + if (( elem = myMesh->FindElement( faceNodesVec, SMDSAbs_Face, /*noMedium=*/false))) + { + // a face of the polyhedron is present in the mesh + faceID = cgnsID( elem, elem2cgIDByEntity[ elem->GetEntityType() ]); + } + else if ( vol.IsFreeFace( iF )) + { + // the face is not shared by volumes + faceID = cgID++; + ++nbPolygones; + faceData.push_back( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + faceData.push_back( cgnsID( faceNodes[i], n2cgID )); + } + else + { + TPolyhedFace face( faceNodes, nbNodes, cgID ); + faceInSet = faces.insert( faces.end(), face ); + if ( faceInSet->_id == cgID ) // the face encounters for the 1st time + { + faceID = cgID++; + ++nbPolygones; + faceData.push_back( nbNodes ); + for ( int i = 0; i < nbNodes; ++i ) + faceData.push_back( cgnsID( faceNodes[i], n2cgID )); + } + else + { + // the face encounters for the 2nd time; we hope it won't encounter once more, + // for that we can erase it from the set of faces + faceID = -faceInSet->_id; + faces.erase( faceInSet ); + } + } + elemData.push_back( faceID ); + } + } + } + + if ( nbPolygones > 0 ) + { + if ( cg_section_write(_fn, iBase, iZone, "Faces of Polyhedrons", + CGNS_ENUMV( NGON_n ), cgID - nbPolygones, cgID-1, + /*nbndry=*/0, &faceData[0], &iSec) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + } + + if ( cg_section_write(_fn, iBase, iZone, "Polyhedrons", + CGNS_ENUMV( NFACE_n ), cgID, cgID+nbPolyhTreated-1, + /*nbndry=*/0, &elemData[0], &iSec) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true ); + + if ( !myMesh->GetGroups().empty() ) + { + // store CGNS ids of polyhedrons + elem2cgID = &elem2cgIDByEntity[ SMDSEntity_Polyhedra ]; + elemIt = myMesh->elementsIterator(); + while ( elemIt->more() ) + { + elem = elemIt->next(); + if ( elem->GetEntityType() == SMDSEntity_Polyhedra ) + { + if ( elem->GetID() != cgID ) + elem2cgID->insert( elem2cgID->end(), make_pair( elem, cgID )); + ++cgID; + } + } + } + } // write polyhedral volumes + + + // Write groups as boundary conditions + // ------------------------------------ + + const set& groups = myMesh->GetGroups(); + set::const_iterator grpIt = groups.begin(); + set< string > groupNames; groupNames.insert(""); // to avoid duplicated and empty names + for ( ; grpIt != groups.end(); ++grpIt ) + { + const SMESHDS_GroupBase* group = *grpIt; + + // write BC location (default is Vertex) + CGNS_ENUMT( GridLocation_t ) location = CGNS_ENUMV( Vertex ); + if ( group->GetType() != SMDSAbs_Node ) + { + switch ( meshDim ) { + case 3: + switch ( group->GetType() ) { + case SMDSAbs_Volume: location = CGNS_ENUMV( FaceCenter ); break; // !!! + case SMDSAbs_Face: location = CGNS_ENUMV( FaceCenter ); break; // OK + case SMDSAbs_Edge: location = CGNS_ENUMV( EdgeCenter ); break; // OK + default:; + } + break; + case 2: + switch ( group->GetType() ) { + case SMDSAbs_Face: location = CGNS_ENUMV( FaceCenter ); break; // ??? + case SMDSAbs_Edge: location = CGNS_ENUMV( EdgeCenter ); break; // OK + default:; + } + break; + case 1: + location = CGNS_ENUMV( EdgeCenter ); break; // ??? + break; + } + } + + // try to extract type of boundary condition from the group name + string name = group->GetStoreName(); + CGNS_ENUMT( BCType_t ) bcType = getBCType( name ); + while ( !groupNames.insert( name ).second ) + name = (SMESH_Comment( "Group_") << groupNames.size()); + + // write IDs of elements + vector< cgsize_t > pnts; + pnts.reserve( group->Extent() ); + SMDS_ElemIteratorPtr elemIt = group->GetElements(); + while ( elemIt->more() ) + { + const SMDS_MeshElement* elem = elemIt->next(); + pnts.push_back( cgnsID( elem, elem2cgIDByEntity[ elem->GetEntityType() ])); + } + int iBC; + if ( cg_boco_write( _fn, iBase, iZone, name.c_str(), bcType, + CGNS_ENUMV( PointList ), pnts.size(), &pnts[0], &iBC) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */true); + + // write BC location + if ( location != CGNS_ENUMV( Vertex )) + { + if ( cg_boco_gridlocation_write( _fn, iBase, iZone, iBC, location) != CG_OK ) + return addMessage( cg_get_error(), /*fatal = */false); + } + } + return DRS_OK; +} + +//================================================================================ +/*! + * \brief Constructor + */ +//================================================================================ + +DriverCGNS_Write::DriverCGNS_Write(): _fn(0) +{ +} + +//================================================================================ +/*! + * \brief Close the cgns file at destruction + */ +//================================================================================ + +DriverCGNS_Write::~DriverCGNS_Write() +{ + if ( _fn > 0 ) + cg_close( _fn ); +} From 446af08df0dabab0184ea00825f8ffff30e62485 Mon Sep 17 00:00:00 2001 From: "Xia, Qingfeng" Date: Mon, 11 Nov 2019 16:56:26 +0000 Subject: [PATCH 7/7] fork changelog added with subfolder summary --- smesh_changelog.md | 39 ++++++++++++++++++++++++++++++++------- 1 file changed, 32 insertions(+), 7 deletions(-) diff --git a/smesh_changelog.md b/smesh_changelog.md index 8d0c136..62ed5fb 100644 --- a/smesh_changelog.md +++ b/smesh_changelog.md @@ -2,15 +2,20 @@ ## Overview -netgen license? GNU Lesser General Public License v2.1 -salome 9.3 stills use the netgen 5.5 version +### subfolders extracted from salome ++ Trace: Kernel `SalomeLocalTrace` ++ Utils: `SMESHUtils` ++ Basics: come from Kernel module of Salome ++ Misc: ++ the other subfolders: mesh module of Salome ++ swig interfacing and GUI related code are dropped ### C++ standard version must support C++14 -C++11 is reequried by OCCT 7.3 +C++11 is reequired by OCCT 7.3 while netgen 6.2dev requires C++14, `std::enable_if_t` is not available on g++ 5.x @@ -37,12 +42,22 @@ while netgen 6.2dev requires C++14, `std::enable_if_t` is not available on g+ ### Migration to C++17 -Salome code is not yet C++17 ready, esp, the breaking exception declearation change in C++17 +Salome code is C++17 ready, except from some plugin suppressed. , + +esp, the breaking exception declearation change in C++17 *looo* has started working on `c++17: dynamic exception specification -> noexcept(false)` https://github.com/LaughlinResearch/SMESH/pull/13 -However, it seems has not completed + + +### netgen must be patched + +netgen license? GNU Lesser General Public License v2.1 + +salome 9.3 stills use the netgen 5.5 version + +why there is no gmsh plugin? built-in? ### Python binding for salomesmesh @@ -51,12 +66,22 @@ PyOCCT has the binding for salomesmesh, using generated pybind11 wrapping. -## Changelog + + +## Changelog for this fork ### missing dependencies libmetis.so is needed libtbb-dev is needed, added to *conda*, but it is not mentioned in readme. +### CGNS mesh format added + +`libcgns-dev` on debian-like systems, `libcgns-devel` + +`FindCGNS.cmake` is downloaded from paraview project + +windows system is not clear, perhaps just disable it. + ### smesh cmake failed on windows for `pthread` @@ -70,7 +95,7 @@ CMake Error at src/3rdParty/salomesmesh/CMakeLists.txt:150 (message): pthread detect can be removed for windows? in CMake, `UNIX` cover Linux, MacOS? -*src file, has projection preprocessor*, but it is also used by several headers +*src file, has C preprocessor*, but it is also used by several headers qingfeng@qingfeng-ubuntu:/opt/SMESH/inc$ grep -rnw ./ -e "pthread" ./BaseTraceCollector.hxx:33:#include