From 1e70d446aec5607c1d8426f6239288c363d6bd95 Mon Sep 17 00:00:00 2001 From: vdweide Date: Mon, 27 Jan 2025 18:58:37 +0100 Subject: [PATCH 01/15] Do not make a distinction in CPhysicalGeometry anymore between FVM and FEM for reading the grid --- Common/include/geometry/CPhysicalGeometry.hpp | 4 +- Common/src/geometry/CPhysicalGeometry.cpp | 47 ++++++------------- 2 files changed, 16 insertions(+), 35 deletions(-) diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index 5671ceae247..1363c46cc8c 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -285,8 +285,8 @@ class CPhysicalGeometry final : public CGeometry { * \param[in] val_iZone - Domain to be read from the grid file. * \param[in] val_nZone - Total number of domains in the grid file. */ - void Read_Mesh_FVM(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, - unsigned short val_nZone); + void Read_Mesh(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, + unsigned short val_nZone); /*! * \brief Reads for the FEM solver the geometry of the grid and adjust the boundary diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 6bbbaa38e3d..6bddb08e383 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -72,38 +72,18 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig* config, unsigned short val_iZone, string val_mesh_filename = config->GetMesh_FileName(); unsigned short val_format = config->GetMesh_FileFormat(); - /*--- Determine whether or not a FEM discretization is used ---*/ + /*--- Check for a valid mesh format ---*/ - const bool fem_solver = config->GetFEMSolver(); - - /*--- Initialize counters for local/global points & elements ---*/ - - if (fem_solver) { - switch (val_format) { - case SU2: - Read_SU2_Format_Parallel_FEM(config, val_mesh_filename, val_iZone, val_nZone); - break; - - case CGNS_GRID: - Read_CGNS_Format_Parallel_FEM(config, val_mesh_filename, val_iZone, val_nZone); - break; - - default: - SU2_MPI::Error("Unrecognized mesh format specified for the FEM solver!", CURRENT_FUNCTION); - break; - } - } else { - switch (val_format) { - case SU2: - case CGNS_GRID: - case RECTANGLE: - case BOX: - Read_Mesh_FVM(config, val_mesh_filename, val_iZone, val_nZone); - break; - default: - SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION); - break; - } + switch (val_format) { + case SU2: + case CGNS_GRID: + case RECTANGLE: + case BOX: + Read_Mesh(config, val_mesh_filename, val_iZone, val_nZone); + break; + default: + SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION); + break; } /*--- After reading the mesh, assert that the dimension is equal to 2 or 3. ---*/ @@ -3433,8 +3413,8 @@ void CPhysicalGeometry::SetBoundaries(CConfig* config) { delete[] nElem_Bound_Copy; } -void CPhysicalGeometry::Read_Mesh_FVM(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, - unsigned short val_nZone) { +void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, + unsigned short val_nZone) { /*--- Initialize counters for local/global points & elements ---*/ Global_nPoint = 0; @@ -3463,6 +3443,7 @@ void CPhysicalGeometry::Read_Mesh_FVM(CConfig* config, const string& val_mesh_fi /*--- Create a mesh reader to read a CGNS grid into linear partitions. ---*/ unsigned short val_format = config->GetMesh_FileFormat(); + const bool fem_solver = config->GetFEMSolver(); CMeshReaderFVM* MeshFVM = nullptr; switch (val_format) { From 9a408d04345e4348e49cf78b1ca38227ff0e6928 Mon Sep 17 00:00:00 2001 From: vdweide Date: Sat, 1 Feb 2025 09:21:26 +0100 Subject: [PATCH 02/15] Modifications to CPhysicalGeometry such that also for FEM the mesh reader classes will be used --- Common/include/geometry/CPhysicalGeometry.hpp | 8 ++-- .../geometry/meshreader/CBoxMeshReaderFVM.hpp | 4 +- .../meshreader/CCGNSMeshReaderFVM.hpp | 4 +- ...CMeshReaderFVM.hpp => CMeshReaderBase.hpp} | 18 ++++----- .../meshreader/CRectangularMeshReaderFVM.hpp | 4 +- .../meshreader/CSU2ASCIIMeshReaderFVM.hpp | 4 +- Common/src/geometry/CPhysicalGeometry.cpp | 40 +++++++++---------- .../geometry/meshreader/CBoxMeshReaderFVM.cpp | 2 +- .../meshreader/CCGNSMeshReaderFVM.cpp | 2 +- ...CMeshReaderFVM.cpp => CMeshReaderBase.cpp} | 6 +-- .../meshreader/CRectangularMeshReaderFVM.cpp | 2 +- .../meshreader/CSU2ASCIIMeshReaderFVM.cpp | 2 +- Common/src/geometry/meshreader/meson.build | 2 +- 13 files changed, 49 insertions(+), 49 deletions(-) rename Common/include/geometry/meshreader/{CMeshReaderFVM.hpp => CMeshReaderBase.hpp} (92%) rename Common/src/geometry/meshreader/{CMeshReaderFVM.cpp => CMeshReaderBase.cpp} (84%) diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index 1363c46cc8c..a474dcbddd6 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -28,7 +28,7 @@ #pragma once #include "CGeometry.hpp" -#include "meshreader/CMeshReaderFVM.hpp" +#include "meshreader/CMeshReaderBase.hpp" #include "../containers/C2DContainer.hpp" /*! @@ -315,21 +315,21 @@ class CPhysicalGeometry final : public CGeometry { * \param[in] config - definition of the particular problem. * \param[in] mesh - mesh reader object containing the current zone data. */ - void LoadLinearlyPartitionedPoints(CConfig* config, CMeshReaderFVM* mesh); + void LoadLinearlyPartitionedPoints(CConfig* config, CMeshReaderBase* mesh); /*! * \brief Loads the interior volume elements from the mesh reader object into the primal element data structures. * \param[in] config - definition of the particular problem. * \param[in] mesh - mesh reader object containing the current zone data. */ - void LoadLinearlyPartitionedVolumeElements(CConfig* config, CMeshReaderFVM* mesh); + void LoadLinearlyPartitionedVolumeElements(CConfig* config, CMeshReaderBase* mesh); /*! * \brief Loads the boundary elements (markers) from the mesh reader object into the primal element data structures. * \param[in] config - definition of the particular problem. * \param[in] mesh - mesh reader object containing the current zone data. */ - void LoadUnpartitionedSurfaceElements(CConfig* config, CMeshReaderFVM* mesh); + void LoadUnpartitionedSurfaceElements(CConfig* config, CMeshReaderBase* mesh); /*! * \brief Prepares the grid point adjacency based on a linearly partitioned mesh object needed by ParMETIS for graph diff --git a/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp index 4c97369ec35..74956a61bba 100644 --- a/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp @@ -28,14 +28,14 @@ #pragma once -#include "CMeshReaderFVM.hpp" +#include "CMeshReaderBase.hpp" /*! * \class CBoxMeshReaderFVM * \brief Reads a 3D box grid into linear partitions for the finite volume solver (FVM). * \author: T. Economon */ -class CBoxMeshReaderFVM : public CMeshReaderFVM { +class CBoxMeshReaderFVM : public CMeshReaderBase { private: unsigned long nNode; /*!< \brief Number of grid nodes in the x-direction. */ unsigned long mNode; /*!< \brief Number of grid nodes in the y-direction. */ diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp index 6199cb540d5..399e1046922 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp @@ -32,14 +32,14 @@ #include "cgnslib.h" #endif -#include "CMeshReaderFVM.hpp" +#include "CMeshReaderBase.hpp" /*! * \class CCGNSMeshReaderFVM * \brief Reads a CGNS zone into linear partitions for the finite volume solver (FVM). * \author: T. Economon */ -class CCGNSMeshReaderFVM : public CMeshReaderFVM { +class CCGNSMeshReaderFVM : public CMeshReaderBase { private: #ifdef HAVE_CGNS int cgnsFileID; /*!< \brief CGNS file identifier. */ diff --git a/Common/include/geometry/meshreader/CMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CMeshReaderBase.hpp similarity index 92% rename from Common/include/geometry/meshreader/CMeshReaderFVM.hpp rename to Common/include/geometry/meshreader/CMeshReaderBase.hpp index 7980acf39fd..6b81a4a16f8 100644 --- a/Common/include/geometry/meshreader/CMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CMeshReaderBase.hpp @@ -1,8 +1,8 @@ /*! - * \file CMeshReaderFVM.hpp - * \brief Header file for the class CMeshReaderFVM. - * The implementations are in the CMeshReaderFVM.cpp file. + * \file CMeshReaderBase.hpp + * \brief Header file for the class CMeshReaderBase. + * The implementations are in the CMeshReaderBase.cpp file. * \author T. Economon * \version 8.1.0 "Harrier" * @@ -35,11 +35,11 @@ #include "../../CConfig.hpp" /*! - * \class CMeshReaderFVM - * \brief Base class for the mesh zone readers of the finite volume solver (FVM). + * \class CMeshReaderBase + * \brief Base class for the mesh zone readers. * \author T. Economon */ -class CMeshReaderFVM { +class CMeshReaderBase { protected: const int rank; /*!< \brief MPI Rank. */ const int size; /*!< \brief MPI Size. */ @@ -69,14 +69,14 @@ class CMeshReaderFVM { public: /*! - * \brief Constructor of the CMeshReaderFVM class. + * \brief Constructor of the CMeshReaderBase class. * \param[in] val_config - config object for the current zone. * \param[in] val_iZone - Current zone index. * \param[in] val_nZone - Total number of zones. */ - CMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + CMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); - virtual ~CMeshReaderFVM() = default; + virtual ~CMeshReaderBase() = default; /*! * \brief Get the physical dimension of the problem (2 or 3). diff --git a/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp index 54f393b88d8..acdc94b8a43 100644 --- a/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp @@ -28,14 +28,14 @@ #pragma once -#include "CMeshReaderFVM.hpp" +#include "CMeshReaderBase.hpp" /*! * \class CRectangularMeshReaderFVM * \brief Reads a 2D rectangular grid into linear partitions for the finite volume solver (FVM). * \author: T. Economon */ -class CRectangularMeshReaderFVM : public CMeshReaderFVM { +class CRectangularMeshReaderFVM : public CMeshReaderBase { private: unsigned long nNode; /*!< \brief Number of grid nodes in the x-direction. */ unsigned long mNode; /*!< \brief Number of grid nodes in the y-direction. */ diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp index 1be0177b435..0222063fb56 100644 --- a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp @@ -30,14 +30,14 @@ #include -#include "CMeshReaderFVM.hpp" +#include "CMeshReaderBase.hpp" /*! * \class CSU2ASCIIMeshReaderFVM * \brief Reads a native SU2 ASCII grid into linear partitions for the finite volume solver (FVM). * \author T. Economon */ -class CSU2ASCIIMeshReaderFVM : public CMeshReaderFVM { +class CSU2ASCIIMeshReaderFVM : public CMeshReaderBase { private: enum class FileSection { POINTS, ELEMENTS, MARKERS }; /*!< \brief Different sections of the file. */ std::array SectionOrder{}; /*!< \brief Order of the sections in the file. */ diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 6bddb08e383..ee2c5992c04 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -3445,19 +3445,19 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena unsigned short val_format = config->GetMesh_FileFormat(); const bool fem_solver = config->GetFEMSolver(); - CMeshReaderFVM* MeshFVM = nullptr; + CMeshReaderBase* Mesh = nullptr; switch (val_format) { case SU2: - MeshFVM = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); + Mesh = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); break; case CGNS_GRID: - MeshFVM = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); + Mesh = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); break; case RECTANGLE: - MeshFVM = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); + Mesh = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); break; case BOX: - MeshFVM = new CBoxMeshReaderFVM(config, val_iZone, val_nZone); + Mesh = new CBoxMeshReaderFVM(config, val_iZone, val_nZone); break; default: SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION); @@ -3466,7 +3466,7 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena /*--- Store the dimension of the problem ---*/ - nDim = MeshFVM->GetDimension(); + nDim = Mesh->GetDimension(); if (rank == MASTER_NODE) { if (nDim == 2) cout << "Two dimensional problem." << endl; if (nDim == 3) cout << "Three dimensional problem." << endl; @@ -3474,10 +3474,10 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena /*--- Store the local and global number of nodes for this rank. ---*/ - nPoint = MeshFVM->GetNumberOfLocalPoints(); - nPointDomain = MeshFVM->GetNumberOfLocalPoints(); - Global_nPoint = MeshFVM->GetNumberOfGlobalPoints(); - Global_nPointDomain = MeshFVM->GetNumberOfGlobalPoints(); + nPoint = Mesh->GetNumberOfLocalPoints(); + nPointDomain = Mesh->GetNumberOfLocalPoints(); + Global_nPoint = Mesh->GetNumberOfGlobalPoints(); + Global_nPointDomain = Mesh->GetNumberOfGlobalPoints(); if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) { cout << Global_nPoint << " grid points before partitioning." << endl; @@ -3487,9 +3487,9 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena /*--- Store the local and global number of interior elements. ---*/ - nElem = MeshFVM->GetNumberOfLocalElements(); - Global_nElem = MeshFVM->GetNumberOfGlobalElements(); - Global_nElemDomain = MeshFVM->GetNumberOfGlobalElements(); + nElem = Mesh->GetNumberOfLocalElements(); + Global_nElem = Mesh->GetNumberOfGlobalElements(); + Global_nElemDomain = Mesh->GetNumberOfGlobalElements(); if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) { cout << Global_nElem << " volume elements before partitioning." << endl; @@ -3500,9 +3500,9 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena /*--- Load the grid points, volume elements, and surface elements from the mesh object into the proper SU2 data structures. ---*/ - LoadLinearlyPartitionedPoints(config, MeshFVM); - LoadLinearlyPartitionedVolumeElements(config, MeshFVM); - LoadUnpartitionedSurfaceElements(config, MeshFVM); + LoadLinearlyPartitionedPoints(config, Mesh); + LoadLinearlyPartitionedVolumeElements(config, Mesh); + LoadUnpartitionedSurfaceElements(config, Mesh); /*--- Prepare the nodal adjacency structures for ParMETIS. ---*/ @@ -3511,10 +3511,10 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena /*--- Now that we have loaded all information from the mesh, delete the mesh reader object. ---*/ - delete MeshFVM; + delete Mesh; } -void CPhysicalGeometry::LoadLinearlyPartitionedPoints(CConfig* config, CMeshReaderFVM* mesh) { +void CPhysicalGeometry::LoadLinearlyPartitionedPoints(CConfig* config, CMeshReaderBase* mesh) { /*--- Get the linearly partitioned coordinates from the mesh object. ---*/ const auto& gridCoords = mesh->GetLocalPointCoordinates(); @@ -3537,7 +3537,7 @@ void CPhysicalGeometry::LoadLinearlyPartitionedPoints(CConfig* config, CMeshRead } } -void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig* config, CMeshReaderFVM* mesh) { +void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig* config, CMeshReaderBase* mesh) { /*--- Reset the global to local element mapping. ---*/ Global_to_Local_Elem.clear(); @@ -3624,7 +3624,7 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig* config, C reduce(nelem_pyramid, Global_nelem_pyramid); } -void CPhysicalGeometry::LoadUnpartitionedSurfaceElements(CConfig* config, CMeshReaderFVM* mesh) { +void CPhysicalGeometry::LoadUnpartitionedSurfaceElements(CConfig* config, CMeshReaderBase* mesh) { /*--- The master node takes care of loading all markers and surface elements from the file. This information is later put into linear partitions to make its redistribution easier diff --git a/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp index e4ee811eaec..8330f1ea6fe 100644 --- a/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp @@ -30,7 +30,7 @@ #include "../../../include/geometry/meshreader/CBoxMeshReaderFVM.hpp" CBoxMeshReaderFVM::CBoxMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) - : CMeshReaderFVM(val_config, val_iZone, val_nZone) { + : CMeshReaderBase(val_config, val_iZone, val_nZone) { /* The box mesh is always 3D. */ dimension = 3; diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp index cdd06c285d6..1cd2bafd4ed 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp @@ -30,7 +30,7 @@ #include "../../../include/geometry/meshreader/CCGNSMeshReaderFVM.hpp" CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) - : CMeshReaderFVM(val_config, val_iZone, val_nZone) { + : CMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS OpenCGNSFile(config->GetMesh_FileName()); diff --git a/Common/src/geometry/meshreader/CMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CMeshReaderBase.cpp similarity index 84% rename from Common/src/geometry/meshreader/CMeshReaderFVM.cpp rename to Common/src/geometry/meshreader/CMeshReaderBase.cpp index 17069bf7b25..47ef0081e22 100644 --- a/Common/src/geometry/meshreader/CMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CMeshReaderBase.cpp @@ -1,5 +1,5 @@ /*! - * \file CMeshReaderFVM.cpp + * \file CMeshReaderBase.cpp * \brief Helper class that provides the counts for each rank in a linear * partitioning given the global count as input. * \author T. Economon @@ -26,7 +26,7 @@ * License along with SU2. If not, see . */ -#include "../../../include/geometry/meshreader/CMeshReaderFVM.hpp" +#include "../../../include/geometry/meshreader/CMeshReaderBase.hpp" -CMeshReaderFVM::CMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CMeshReaderBase::CMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : rank(SU2_MPI::GetRank()), size(SU2_MPI::GetSize()), config(val_config) {} diff --git a/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp index 5b89744bf2a..971fe37fbbd 100644 --- a/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp @@ -31,7 +31,7 @@ CRectangularMeshReaderFVM::CRectangularMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) - : CMeshReaderFVM(val_config, val_iZone, val_nZone) { + : CMeshReaderBase(val_config, val_iZone, val_nZone) { /* The rectangular mesh is always 2D. */ dimension = 2; diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp index e0ebfcc5acb..00307a90d94 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp @@ -30,7 +30,7 @@ #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) - : CMeshReaderFVM(val_config, val_iZone, val_nZone), + : CMeshReaderBase(val_config, val_iZone, val_nZone), myZone(val_iZone), nZones(val_nZone), meshFilename(config->GetMesh_FileName()) { diff --git a/Common/src/geometry/meshreader/meson.build b/Common/src/geometry/meshreader/meson.build index 3f1e12595de..fb44650ad56 100644 --- a/Common/src/geometry/meshreader/meson.build +++ b/Common/src/geometry/meshreader/meson.build @@ -1,5 +1,5 @@ common_src += files(['CBoxMeshReaderFVM.cpp', 'CCGNSMeshReaderFVM.cpp', - 'CMeshReaderFVM.cpp', + 'CMeshReaderBase.cpp', 'CRectangularMeshReaderFVM.cpp', 'CSU2ASCIIMeshReaderFVM.cpp']) From 8bc3462fd98700736b46c16e7d399c7fbf30ef5b Mon Sep 17 00:00:00 2001 From: vdweide Date: Sat, 1 Feb 2025 12:37:01 +0100 Subject: [PATCH 03/15] Split the CGNS finite volume reader in a common base class and a class that is specific to the reading of the CGNS grid for the finite volume solver --- .../meshreader/CCGNSMeshReaderBase.hpp | 108 +++++ .../meshreader/CCGNSMeshReaderFVM.hpp | 59 +-- .../meshreader/CCGNSMeshReaderBase.cpp | 410 ++++++++++++++++++ .../meshreader/CCGNSMeshReaderFVM.cpp | 362 +--------------- Common/src/geometry/meshreader/meson.build | 1 + 5 files changed, 522 insertions(+), 418 deletions(-) create mode 100644 Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp create mode 100644 Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp new file mode 100644 index 00000000000..ef12386e12c --- /dev/null +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp @@ -0,0 +1,108 @@ +/*! + * \file CCGNSMeshReaderBase.hpp + * \brief Header file for the class CCGNSMeshReaderBase. + * The implementations are in the CCGNSMeshReaderBase.cpp file. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#ifdef HAVE_CGNS +#include "cgnslib.h" +#endif + +#include "CMeshReaderBase.hpp" + +/*! + * \class CCGNSMeshReaderBase + * \brief Base class for the reading of a CGNS zone. + * \author: T. Economon + */ +class CCGNSMeshReaderBase : public CMeshReaderBase { + protected: +#ifdef HAVE_CGNS + int cgnsFileID; /*!< \brief CGNS file identifier. */ + const int cgnsBase = 1; /*!< \brief CGNS database index (the CGNS reader currently assumes a single database). */ + const int cgnsZone = 1; /*!< \brief CGNS zone index (and 1 zone in that database). */ + + int nSections; /*!< \brief Total number of sections in the CGNS file. */ + + vector isInterior; /*!< \brief Vector of booleans to store whether each section in the CGNS file is an interior + or boundary section. */ + vector + nElems; /*!< \brief Vector containing the local number of elements found within each CGNS section. */ + vector elemOffset; /*!< \brief Global ID offset for each interior section (i.e., the total number of + global elements that came before it). */ + vector > connElems; /*!< \brief Vector containing the local element connectivity found within each + CGNS section. First index is the section, second contains the connectivity in + format [globalID VTK n1 n2 n3 n4 n5 n6 n7 n8] for each element. */ + vector > sectionNames; /*!< \brief Vector for storing the names of each boundary section (marker). */ + + /*! + * \brief Open the CGNS file and checks for errors. + * \param[in] val_filename - string name of the CGNS file to be read. + */ + void OpenCGNSFile(const string& val_filename); + + /*! + * \brief Reads all CGNS database metadata and checks for errors. + */ + void ReadCGNSDatabaseMetadata(); + + /*! + * \brief Reads all CGNS zone metadata and checks for errors. + */ + void ReadCGNSZoneMetadata(); + + /*! + * \brief Reads the grid points from a CGNS zone into linear partitions across all ranks. + */ + void ReadCGNSPointCoordinates(); + + /*! + * \brief Reads the metadata for each CGNS section in a zone and collect information, including the size and whether + * it is an interior or boundary section. + */ + void ReadCGNSSectionMetadata(); + + /*! + * \brief Get the VTK type and string name for a CGNS element type. + * \param[in] val_elem_type - CGNS element type. + * \param[out] val_vtk_type - VTK type identifier index. + * \returns String containing the name of the element type. + */ + string GetCGNSElementType(ElementType_t val_elem_type, int& val_vtk_type); +#endif + + public: + /*! + * \brief Constructor of the CCGNSMeshReaderBase class. + */ + CCGNSMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CCGNSMeshReaderBase class. + */ + virtual ~CCGNSMeshReaderBase(void) override; +}; diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp index 399e1046922..4edb6cbf27c 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp @@ -28,64 +28,16 @@ #pragma once -#ifdef HAVE_CGNS -#include "cgnslib.h" -#endif - -#include "CMeshReaderBase.hpp" +#include "CCGNSMeshReaderBase.hpp" /*! * \class CCGNSMeshReaderFVM * \brief Reads a CGNS zone into linear partitions for the finite volume solver (FVM). * \author: T. Economon */ -class CCGNSMeshReaderFVM : public CMeshReaderBase { +class CCGNSMeshReaderFVM : public CCGNSMeshReaderBase { private: #ifdef HAVE_CGNS - int cgnsFileID; /*!< \brief CGNS file identifier. */ - const int cgnsBase = 1; /*!< \brief CGNS database index (the CGNS reader currently assumes a single database). */ - const int cgnsZone = 1; /*!< \brief CGNS zone index (and 1 zone in that database). */ - - int nSections; /*!< \brief Total number of sections in the CGNS file. */ - - vector isInterior; /*!< \brief Vector of booleans to store whether each section in the CGNS file is an interior - or boundary section. */ - vector - nElems; /*!< \brief Vector containing the local number of elements found within each CGNS section. */ - vector elemOffset; /*!< \brief Global ID offset for each interior section (i.e., the total number of - global elements that came before it). */ - vector > connElems; /*!< \brief Vector containing the local element connectivity found within each - CGNS section. First index is the section, second contains the connectivity in - format [globalID VTK n1 n2 n3 n4 n5 n6 n7 n8] for each element. */ - vector > sectionNames; /*!< \brief Vector for storing the names of each boundary section (marker). */ - - /*! - * \brief Open the CGNS file and checks for errors. - * \param[in] val_filename - string name of the CGNS file to be read. - */ - void OpenCGNSFile(const string& val_filename); - - /*! - * \brief Reads all CGNS database metadata and checks for errors. - */ - void ReadCGNSDatabaseMetadata(); - - /*! - * \brief Reads all CGNS zone metadata and checks for errors. - */ - void ReadCGNSZoneMetadata(); - - /*! - * \brief Reads the grid points from a CGNS zone into linear partitions across all ranks. - */ - void ReadCGNSPointCoordinates(); - - /*! - * \brief Reads the metadata for each CGNS section in a zone and collect information, including the size and whether - * it is an interior or boundary section. - */ - void ReadCGNSSectionMetadata(); - /*! * \brief Reads the interior volume elements from one section of a CGNS zone into linear partitions across all ranks. * \param[in] val_section - CGNS section index. @@ -108,13 +60,6 @@ class CCGNSMeshReaderFVM : public CMeshReaderBase { */ void ReformatCGNSSurfaceConnectivity(); - /*! - * \brief Get the VTK type and string name for a CGNS element type. - * \param[in] val_elem_type - CGNS element type. - * \param[out] val_vtk_type - VTK type identifier index. - * \returns String containing the name of the element type. - */ - string GetCGNSElementType(ElementType_t val_elem_type, int& val_vtk_type); #endif /*! diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp new file mode 100644 index 00000000000..8a0f4e2bdb6 --- /dev/null +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp @@ -0,0 +1,410 @@ +/*! + * \file CCGNSMeshReaderBase.cpp + * \brief Helper class for the reading of a CGNS grid file. + * linear partitions across all ranks. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#include "../../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../../include/geometry/meshreader/CCGNSMeshReaderBase.hpp" + +CCGNSMeshReaderBase::CCGNSMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) + : CMeshReaderBase(val_config, val_iZone, val_nZone) { +#ifdef HAVE_CGNS + /*--- Leave the option to do something in the future here. ---*/ +#else + SU2_MPI::Error(string(" SU2 built without CGNS support. \n") + string(" To use CGNS, build SU2 accordingly."), + CURRENT_FUNCTION); +#endif +} + +CCGNSMeshReaderBase::~CCGNSMeshReaderBase() = default; + +#ifdef HAVE_CGNS +void CCGNSMeshReaderBase::OpenCGNSFile(const string& val_filename) { + /*--- Check whether the supplied file is truly a CGNS file. ---*/ + + int file_type; + float file_version; + if (cg_is_cgns(val_filename.c_str(), &file_type) != CG_OK) { + SU2_MPI::Error(val_filename + string(" was not found or is not a properly formatted") + + string(" CGNS file.\nNote that SU2 expects unstructured") + + string(" CGNS files in ADF data format."), + CURRENT_FUNCTION); + } + + /*--- Open the CGNS file for reading. The value of cgnsFileID returned + is the specific index number for this file and will be + repeatedly used in the function calls. ---*/ + + if (cg_open(val_filename.c_str(), CG_MODE_READ, &cgnsFileID)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Reading the CGNS file: "; + cout << val_filename.c_str() << "." << endl; + } + if (cg_version(cgnsFileID, &file_version)) cg_error_exit(); + if (rank == MASTER_NODE) { + if (file_version < 4.0) { + cout + << "WARNING: The CGNS file version (" << file_version + << ") is old and may cause high memory usage issues, consider updating the file with the cgnsupdate tool.\n"; + } + } +} + +void CCGNSMeshReaderBase::ReadCGNSDatabaseMetadata() { + /*--- Get the number of databases. This is the highest node + in the CGNS heirarchy. ---*/ + + int nbases; + if (cg_nbases(cgnsFileID, &nbases)) cg_error_exit(); + if (rank == MASTER_NODE) cout << "CGNS file contains " << nbases << " database(s)." << endl; + + /*--- Check if there is more than one database. Throw an + error if there is because this reader can currently + only handle one database. ---*/ + + if (nbases > 1) { + SU2_MPI::Error("CGNS reader currently can only handle 1 database.", CURRENT_FUNCTION); + } + + /*--- Read the database. Note that the CGNS indexing starts at 1. ---*/ + + int cell_dim, phys_dim; + char basename[CGNS_STRING_SIZE]; + if (cg_base_read(cgnsFileID, cgnsBase, basename, &cell_dim, &phys_dim)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Database " << cgnsBase << ", " << basename << ": "; + cout << " cell dimension of " << cell_dim << ", physical "; + cout << "dimension of " << phys_dim << "." << endl; + } + + /*--- Set the number of dimensions baed on cell_dim. ---*/ + + dimension = (unsigned short)cell_dim; +} + +void CCGNSMeshReaderBase::ReadCGNSZoneMetadata() { + /*--- First, check all sections to find the element types and to + classify them as either surface or volume elements. We will also + perform some error checks here to avoid partitioning issues. ---*/ + + /*--- Get the number of zones for this base. ---*/ + + int nzones; + if (cg_nzones(cgnsFileID, cgnsBase, &nzones)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << nzones << " total zone(s)." << endl; + } + + /*--- Check if there is more than one zone. Until we enable it, we + will require a single zone CGNS file. Multizone problems can still + be run with CGNS by using separate CGNS files for each zone. ---*/ + + if (nzones > 1) { + SU2_MPI::Error(string("CGNS reader currently expects only 1 zone per CGNS file.") + + string("Multizone problems can be run with separate CGNS files for each zone."), + CURRENT_FUNCTION); + } + + /*--- Read the basic information for this zone, including + the name and the number of vertices, cells, and + boundary cells which are stored in the cgsize variable. ---*/ + + vector cgsize(3); + ZoneType_t zonetype; + char zonename[CGNS_STRING_SIZE]; + if (cg_zone_read(cgnsFileID, cgnsBase, cgnsZone, zonename, cgsize.data())) cg_error_exit(); + + /*--- Rename the zone size information for clarity. + NOTE: The number of cells here may be only the number of + interior elements or it may be the total. This needs to + be counted explicitly later. ---*/ + + numberOfGlobalPoints = cgsize[0]; + int nElemCGNS = cgsize[1]; + + /*--- Get some additional information about the current zone. ---*/ + + if (cg_zone_type(cgnsFileID, cgnsBase, cgnsZone, &zonetype)) cg_error_exit(); + + /*--- Check for an unstructured mesh. Throw an error if not found. ---*/ + + if (zonetype != Unstructured) + SU2_MPI::Error("Structured CGNS zone found while unstructured expected.", CURRENT_FUNCTION); + + /*--- Print current zone info to the console. ---*/ + + if (rank == MASTER_NODE) { + cout << "Zone " << cgnsZone << ", " << zonename << ": "; + cout << numberOfGlobalPoints << " total vertices, "; + cout << nElemCGNS << " total elements." << endl; + } + + /*--- Retrieve the number of grids in this zone. For now, we know + this is one, but to be more general, this will need to check and + allow for a loop over all grids. ---*/ + + int ngrids; + if (cg_ngrids(cgnsFileID, cgnsBase, cgnsZone, &ngrids)) cg_error_exit(); + if (ngrids > 1) { + SU2_MPI::Error("CGNS reader currently handles only 1 grid per zone.", CURRENT_FUNCTION); + } +} + +void CCGNSMeshReaderBase::ReadCGNSPointCoordinates() { + /*--- Compute the number of points that will be on each processor. + This is a linear partitioning with the addition of a simple load + balancing for any remainder points. ---*/ + + CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); + + /*--- Store the local number of nodes for this rank. ---*/ + + numberOfLocalPoints = pointPartitioner.GetSizeOnRank(rank); + + /*--- Create buffer to hold the grid coordinates for our rank. ---*/ + + localPointCoordinates.resize(dimension); + for (int k = 0; k < dimension; k++) localPointCoordinates[k].resize(numberOfLocalPoints, 0.0); + + /*--- Set the value of range_max to the total number of nodes in + the unstructured mesh. Also allocate memory for the temporary array + that will hold the grid coordinates as they are extracted. Note the + +1 for CGNS convention. ---*/ + + cgsize_t range_min = (cgsize_t)pointPartitioner.GetFirstIndexOnRank(rank) + 1; + auto range_max = (cgsize_t)pointPartitioner.GetLastIndexOnRank(rank); + + /*--- Loop over each set of coordinates. ---*/ + + for (int k = 0; k < dimension; k++) { + /*--- Read the coordinate info. This will retrieve the + data type (either RealSingle or RealDouble) as + well as the coordname which will specify the + type of data that it is based in the SIDS convention. + This might be "CoordinateX," for instance. ---*/ + + char coordname[CGNS_STRING_SIZE]; + DataType_t datatype; + if (cg_coord_info(cgnsFileID, cgnsBase, cgnsZone, k + 1, &datatype, coordname)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Loading " << coordname; + if (size > SINGLE_NODE) { + cout << " values into linear partitions." << endl; + } else { + cout << " values." << endl; + } + } + + /*--- Check the coordinate name to decide the index for storage. ---*/ + + unsigned short indC = 0; + if (string(coordname) == "CoordinateX") + indC = 0; + else if (string(coordname) == "CoordinateY") + indC = 1; + else if (string(coordname) == "CoordinateZ") + indC = 2; + else + SU2_MPI::Error(string("Unknown coordinate name, ") + coordname + string(", in the CGNS file."), CURRENT_FUNCTION); + + /*--- Now read our rank's chunk of coordinates from the file. + Ask for datatype RealDouble and let CGNS library do the translation + when RealSingle is found. ---*/ + + if (cg_coord_read(cgnsFileID, cgnsBase, cgnsZone, coordname, RealDouble, &range_min, &range_max, + localPointCoordinates[indC].data())) + cg_error_exit(); + } +} + +void CCGNSMeshReaderBase::ReadCGNSSectionMetadata() { + /*--- Begin section for retrieving the connectivity info. ---*/ + + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) cout << "Distributing connectivity across all ranks." << endl; + + /*--- First check the number of sections. ---*/ + + if (cg_nsections(cgnsFileID, cgnsBase, cgnsZone, &nSections)) cg_error_exit(); + if (rank == MASTER_NODE) { + cout << "Number of connectivity sections is "; + cout << nSections << "." << endl; + } + + /*--- Prepare several data structures to hold the various + pieces of information describing each section. ---*/ + + isInterior.resize(nSections); + nElems.resize(nSections, 0); + elemOffset.resize(nSections + 1, 0); + elemOffset[0] = 0; + connElems.resize(nSections); + sectionNames.resize(nSections, vector(CGNS_STRING_SIZE)); + numberOfGlobalElements = 0; + + for (int s = 0; s < nSections; s++) { + /*--- Read the connectivity details for this section. ---*/ + + int nbndry, parent_flag, vtk_type; + cgsize_t startE, endE, sizeNeeded; + ElementType_t elemType; + if (cg_section_read(cgnsFileID, cgnsBase, cgnsZone, s + 1, sectionNames[s].data(), &elemType, &startE, &endE, + &nbndry, &parent_flag)) + cg_error_exit(); + + /*--- Compute the total element count in this section (global). ---*/ + + unsigned long element_count = (endE - startE + 1); + + /* Get the details for the CGNS element type in this section. */ + + string elem_name = GetCGNSElementType(elemType, vtk_type); + + /* We assume that each section contains interior elements by default. + If we find 1D elements in a 2D problem or 2D elements in a 3D + problem, then we know the section must contain boundary elements. + We assume that each section is composed of either entirely interior + or entirely boundary elements. */ + + isInterior[s] = true; + + if (elemType == MIXED) { + /* For a mixed section, we check the type of the first element + so that we can correctly label this section as an interior or + boundary element section. Here, we also assume that a section + can not hold both interior and boundary elements. First, get + the size required to read a single element from the section. */ + + if (cg_ElementPartialSize(cgnsFileID, cgnsBase, cgnsZone, s + 1, startE, startE, &sizeNeeded) != CG_OK) + cg_error_exit(); + + /* A couple of auxiliary vectors for mixed element sections. */ + + vector connElemCGNS(sizeNeeded); + vector connOffsetCGNS(2, 0); + + /* Retrieve the connectivity information for the first element. */ + + if (cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, s + 1, startE, startE, connElemCGNS.data(), + connOffsetCGNS.data(), nullptr) != CG_OK) + cg_error_exit(); + + /* The element type is in the first position of the connectivity + information that we retrieved from the CGNS file. */ + + elemType = ElementType_t(connElemCGNS[0]); + } + + /* Check for 1D elements in 2D problems, or for 2D elements in + 3D problems. If found, mark the section as a boundary section. */ + + if ((dimension == 2) && (elemType == BAR_2 || elemType == BAR_3)) isInterior[s] = false; + if ((dimension == 3) && (elemType == TRI_3 || elemType == QUAD_4)) isInterior[s] = false; + + /*--- Increment the global element offset for each section + based on whether or not this is a surface or volume section. + We also keep a running count of the total elements globally. ---*/ + + elemOffset[s + 1] = elemOffset[s]; + if (!isInterior[s]) + elemOffset[s + 1] += element_count; + else + numberOfGlobalElements += element_count; + + /*--- Print some information to the console. ---*/ + + if (rank == MASTER_NODE) { + cout << "Section " << string(sectionNames[s].data()); + cout << " contains " << element_count << " elements"; + cout << " of type " << elem_name << "." << endl; + } + } +} + +string CCGNSMeshReaderBase::GetCGNSElementType(ElementType_t val_elem_type, int& val_vtk_type) { + /* Check the CGNS element type and return the string name + for the element and the associated VTK type index. */ + + string elem_name; + switch (val_elem_type) { + case NODE: + elem_name = "Vertex"; + val_vtk_type = 1; + SU2_MPI::Error("Vertex elements detected. Please remove.", CURRENT_FUNCTION); + break; + case BAR_2: case BAR_3: case BAR_4: case BAR_5: + elem_name = "Line"; + val_vtk_type = 3; + if (dimension == 3) + SU2_MPI::Error("Line elements detected in a 3D mesh. Please remove.", + CURRENT_FUNCTION); + break; + case TRI_3: case TRI_6: case TRI_9: case TRI_10: + case TRI_12: case TRI_15: + elem_name = "Triangle"; + val_vtk_type = 5; + break; + case QUAD_4: case QUAD_8: case QUAD_9: case QUAD_12: + case QUAD_16: case QUAD_P4_16: case QUAD_25: + elem_name = "Quadrilateral"; + val_vtk_type = 9; + break; + case TETRA_4: case TETRA_10: case TETRA_16: case TETRA_20: + case TETRA_22: case TETRA_34: case TETRA_35: + elem_name = "Tetrahedron"; + val_vtk_type = 10; + break; + case HEXA_8: case HEXA_20: case HEXA_27: case HEXA_32: + case HEXA_56: case HEXA_64: case HEXA_44: case HEXA_98: + case HEXA_125: + elem_name = "Hexahedron"; + val_vtk_type = 12; + break; + case PENTA_6: case PENTA_15: case PENTA_18: case PENTA_24: + case PENTA_38: case PENTA_40: case PENTA_33: case PENTA_66: + case PENTA_75: + elem_name = "Prism"; + val_vtk_type = 13; + break; + case PYRA_5: case PYRA_14: case PYRA_13: case PYRA_21: + case PYRA_29: case PYRA_30: case PYRA_P4_29: case PYRA_50: + case PYRA_55: + elem_name = "Pyramid"; + val_vtk_type = 14; + break; + case MIXED: + elem_name = "Mixed"; + val_vtk_type = -1; + break; + default: + char buf[100]; + SPRINTF(buf, "Unsupported or unknown CGNS element type: (type %d)\n", val_elem_type); + SU2_MPI::Error(string(buf), CURRENT_FUNCTION); + break; + } + + return elem_name; +} +#endif \ No newline at end of file diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp index 1cd2bafd4ed..147f5de0323 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp @@ -30,7 +30,7 @@ #include "../../../include/geometry/meshreader/CCGNSMeshReaderFVM.hpp" CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) - : CMeshReaderBase(val_config, val_iZone, val_nZone) { + : CCGNSMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS OpenCGNSFile(config->GetMesh_FileName()); @@ -74,307 +74,6 @@ CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_i CCGNSMeshReaderFVM::~CCGNSMeshReaderFVM() = default; #ifdef HAVE_CGNS -void CCGNSMeshReaderFVM::OpenCGNSFile(const string& val_filename) { - /*--- Check whether the supplied file is truly a CGNS file. ---*/ - - int file_type; - float file_version; - if (cg_is_cgns(val_filename.c_str(), &file_type) != CG_OK) { - SU2_MPI::Error(val_filename + string(" was not found or is not a properly formatted") + - string(" CGNS file.\nNote that SU2 expects unstructured") + - string(" CGNS files in ADF data format."), - CURRENT_FUNCTION); - } - - /*--- Open the CGNS file for reading. The value of cgnsFileID returned - is the specific index number for this file and will be - repeatedly used in the function calls. ---*/ - - if (cg_open(val_filename.c_str(), CG_MODE_READ, &cgnsFileID)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Reading the CGNS file: "; - cout << val_filename.c_str() << "." << endl; - } - if (cg_version(cgnsFileID, &file_version)) cg_error_exit(); - if (rank == MASTER_NODE) { - if (file_version < 4.0) { - cout - << "WARNING: The CGNS file version (" << file_version - << ") is old and may cause high memory usage issues, consider updating the file with the cgnsupdate tool.\n"; - } - } -} - -void CCGNSMeshReaderFVM::ReadCGNSDatabaseMetadata() { - /*--- Get the number of databases. This is the highest node - in the CGNS heirarchy. ---*/ - - int nbases; - if (cg_nbases(cgnsFileID, &nbases)) cg_error_exit(); - if (rank == MASTER_NODE) cout << "CGNS file contains " << nbases << " database(s)." << endl; - - /*--- Check if there is more than one database. Throw an - error if there is because this reader can currently - only handle one database. ---*/ - - if (nbases > 1) { - SU2_MPI::Error("CGNS reader currently can only handle 1 database.", CURRENT_FUNCTION); - } - - /*--- Read the database. Note that the CGNS indexing starts at 1. ---*/ - - int cell_dim, phys_dim; - char basename[CGNS_STRING_SIZE]; - if (cg_base_read(cgnsFileID, cgnsBase, basename, &cell_dim, &phys_dim)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Database " << cgnsBase << ", " << basename << ": "; - cout << " cell dimension of " << cell_dim << ", physical "; - cout << "dimension of " << phys_dim << "." << endl; - } - - /*--- Set the number of dimensions baed on cell_dim. ---*/ - - dimension = (unsigned short)cell_dim; -} - -void CCGNSMeshReaderFVM::ReadCGNSZoneMetadata() { - /*--- First, check all sections to find the element types and to - classify them as either surface or volume elements. We will also - perform some error checks here to avoid partitioning issues. ---*/ - - /*--- Get the number of zones for this base. ---*/ - - int nzones; - if (cg_nzones(cgnsFileID, cgnsBase, &nzones)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << nzones << " total zone(s)." << endl; - } - - /*--- Check if there is more than one zone. Until we enable it, we - will require a single zone CGNS file. Multizone problems can still - be run with CGNS by using separate CGNS files for each zone. ---*/ - - if (nzones > 1) { - SU2_MPI::Error(string("CGNS reader currently expects only 1 zone per CGNS file.") + - string("Multizone problems can be run with separate CGNS files for each zone."), - CURRENT_FUNCTION); - } - - /*--- Read the basic information for this zone, including - the name and the number of vertices, cells, and - boundary cells which are stored in the cgsize variable. ---*/ - - vector cgsize(3); - ZoneType_t zonetype; - char zonename[CGNS_STRING_SIZE]; - if (cg_zone_read(cgnsFileID, cgnsBase, cgnsZone, zonename, cgsize.data())) cg_error_exit(); - - /*--- Rename the zone size information for clarity. - NOTE: The number of cells here may be only the number of - interior elements or it may be the total. This needs to - be counted explicitly later. ---*/ - - numberOfGlobalPoints = cgsize[0]; - int nElemCGNS = cgsize[1]; - - /*--- Get some additional information about the current zone. ---*/ - - if (cg_zone_type(cgnsFileID, cgnsBase, cgnsZone, &zonetype)) cg_error_exit(); - - /*--- Check for an unstructured mesh. Throw an error if not found. ---*/ - - if (zonetype != Unstructured) - SU2_MPI::Error("Structured CGNS zone found while unstructured expected.", CURRENT_FUNCTION); - - /*--- Print current zone info to the console. ---*/ - - if (rank == MASTER_NODE) { - cout << "Zone " << cgnsZone << ", " << zonename << ": "; - cout << numberOfGlobalPoints << " total vertices, "; - cout << nElemCGNS << " total elements." << endl; - } - - /*--- Retrieve the number of grids in this zone. For now, we know - this is one, but to be more general, this will need to check and - allow for a loop over all grids. ---*/ - - int ngrids; - if (cg_ngrids(cgnsFileID, cgnsBase, cgnsZone, &ngrids)) cg_error_exit(); - if (ngrids > 1) { - SU2_MPI::Error("CGNS reader currently handles only 1 grid per zone.", CURRENT_FUNCTION); - } -} - -void CCGNSMeshReaderFVM::ReadCGNSPointCoordinates() { - /*--- Compute the number of points that will be on each processor. - This is a linear partitioning with the addition of a simple load - balancing for any remainder points. ---*/ - - CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); - - /*--- Store the local number of nodes for this rank. ---*/ - - numberOfLocalPoints = pointPartitioner.GetSizeOnRank(rank); - - /*--- Create buffer to hold the grid coordinates for our rank. ---*/ - - localPointCoordinates.resize(dimension); - for (int k = 0; k < dimension; k++) localPointCoordinates[k].resize(numberOfLocalPoints, 0.0); - - /*--- Set the value of range_max to the total number of nodes in - the unstructured mesh. Also allocate memory for the temporary array - that will hold the grid coordinates as they are extracted. Note the - +1 for CGNS convention. ---*/ - - cgsize_t range_min = (cgsize_t)pointPartitioner.GetFirstIndexOnRank(rank) + 1; - auto range_max = (cgsize_t)pointPartitioner.GetLastIndexOnRank(rank); - - /*--- Loop over each set of coordinates. ---*/ - - for (int k = 0; k < dimension; k++) { - /*--- Read the coordinate info. This will retrieve the - data type (either RealSingle or RealDouble) as - well as the coordname which will specify the - type of data that it is based in the SIDS convention. - This might be "CoordinateX," for instance. ---*/ - - char coordname[CGNS_STRING_SIZE]; - DataType_t datatype; - if (cg_coord_info(cgnsFileID, cgnsBase, cgnsZone, k + 1, &datatype, coordname)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Loading " << coordname; - if (size > SINGLE_NODE) { - cout << " values into linear partitions." << endl; - } else { - cout << " values." << endl; - } - } - - /*--- Check the coordinate name to decide the index for storage. ---*/ - - unsigned short indC = 0; - if (string(coordname) == "CoordinateX") - indC = 0; - else if (string(coordname) == "CoordinateY") - indC = 1; - else if (string(coordname) == "CoordinateZ") - indC = 2; - else - SU2_MPI::Error(string("Unknown coordinate name, ") + coordname + string(", in the CGNS file."), CURRENT_FUNCTION); - - /*--- Now read our rank's chunk of coordinates from the file. - Ask for datatype RealDouble and let CGNS library do the translation - when RealSingle is found. ---*/ - - if (cg_coord_read(cgnsFileID, cgnsBase, cgnsZone, coordname, RealDouble, &range_min, &range_max, - localPointCoordinates[indC].data())) - cg_error_exit(); - } -} - -void CCGNSMeshReaderFVM::ReadCGNSSectionMetadata() { - /*--- Begin section for retrieving the connectivity info. ---*/ - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) cout << "Distributing connectivity across all ranks." << endl; - - /*--- First check the number of sections. ---*/ - - if (cg_nsections(cgnsFileID, cgnsBase, cgnsZone, &nSections)) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Number of connectivity sections is "; - cout << nSections << "." << endl; - } - - /*--- Prepare several data structures to hold the various - pieces of information describing each section. ---*/ - - isInterior.resize(nSections); - nElems.resize(nSections, 0); - elemOffset.resize(nSections + 1, 0); - elemOffset[0] = 0; - connElems.resize(nSections); - sectionNames.resize(nSections, vector(CGNS_STRING_SIZE)); - numberOfGlobalElements = 0; - - for (int s = 0; s < nSections; s++) { - /*--- Read the connectivity details for this section. ---*/ - - int nbndry, parent_flag, vtk_type; - cgsize_t startE, endE, sizeNeeded; - ElementType_t elemType; - if (cg_section_read(cgnsFileID, cgnsBase, cgnsZone, s + 1, sectionNames[s].data(), &elemType, &startE, &endE, - &nbndry, &parent_flag)) - cg_error_exit(); - - /*--- Compute the total element count in this section (global). ---*/ - - unsigned long element_count = (endE - startE + 1); - - /* Get the details for the CGNS element type in this section. */ - - string elem_name = GetCGNSElementType(elemType, vtk_type); - - /* We assume that each section contains interior elements by default. - If we find 1D elements in a 2D problem or 2D elements in a 3D - problem, then we know the section must contain boundary elements. - We assume that each section is composed of either entirely interior - or entirely boundary elements. */ - - isInterior[s] = true; - - if (elemType == MIXED) { - /* For a mixed section, we check the type of the first element - so that we can correctly label this section as an interior or - boundary element section. Here, we also assume that a section - can not hold both interior and boundary elements. First, get - the size required to read a single element from the section. */ - - if (cg_ElementPartialSize(cgnsFileID, cgnsBase, cgnsZone, s + 1, startE, startE, &sizeNeeded) != CG_OK) - cg_error_exit(); - - /* A couple of auxiliary vectors for mixed element sections. */ - - vector connElemCGNS(sizeNeeded); - vector connOffsetCGNS(2, 0); - - /* Retrieve the connectivity information for the first element. */ - - if (cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, s + 1, startE, startE, connElemCGNS.data(), - connOffsetCGNS.data(), nullptr) != CG_OK) - cg_error_exit(); - - /* The element type is in the first position of the connectivity - information that we retrieved from the CGNS file. */ - - elemType = ElementType_t(connElemCGNS[0]); - } - - /* Check for 1D elements in 2D problems, or for 2D elements in - 3D problems. If found, mark the section as a boundary section. */ - - if ((dimension == 2) && (elemType == BAR_2 || elemType == BAR_3)) isInterior[s] = false; - if ((dimension == 3) && (elemType == TRI_3 || elemType == QUAD_4)) isInterior[s] = false; - - /*--- Increment the global element offset for each section - based on whether or not this is a surface or volume section. - We also keep a running count of the total elements globally. ---*/ - - elemOffset[s + 1] = elemOffset[s]; - if (!isInterior[s]) - elemOffset[s + 1] += element_count; - else - numberOfGlobalElements += element_count; - - /*--- Print some information to the console. ---*/ - - if (rank == MASTER_NODE) { - cout << "Section " << string(sectionNames[s].data()); - cout << " contains " << element_count << " elements"; - cout << " of type " << elem_name << "." << endl; - } - } -} - void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { /*--- In this routine, each rank will read a chunk of the element connectivity for a single specified section of the CGNS mesh file. @@ -951,65 +650,6 @@ void CCGNSMeshReaderFVM::ReformatCGNSSurfaceConnectivity() { } } } - -string CCGNSMeshReaderFVM::GetCGNSElementType(ElementType_t val_elem_type, int& val_vtk_type) { - /* Check the CGNS element type and return the string name - for the element and the associated VTK type index. */ - - string elem_name; - switch (val_elem_type) { - case NODE: - elem_name = "Vertex"; - val_vtk_type = 1; - SU2_MPI::Error("Vertex elements detected. Please remove.", CURRENT_FUNCTION); - break; - case BAR_2: - elem_name = "Line"; - val_vtk_type = 3; - if (dimension == 3) SU2_MPI::Error("Line elements detected in a 3D mesh. Please remove.", CURRENT_FUNCTION); - break; - case BAR_3: - elem_name = "Line"; - val_vtk_type = 3; - if (dimension == 3) SU2_MPI::Error("Line elements detected in a 3D mesh. Please remove.", CURRENT_FUNCTION); - break; - case TRI_3: - elem_name = "Triangle"; - val_vtk_type = 5; - break; - case QUAD_4: - elem_name = "Quadrilateral"; - val_vtk_type = 9; - break; - case TETRA_4: - elem_name = "Tetrahedron"; - val_vtk_type = 10; - break; - case HEXA_8: - elem_name = "Hexahedron"; - val_vtk_type = 12; - break; - case PENTA_6: - elem_name = "Prism"; - val_vtk_type = 13; - break; - case PYRA_5: - elem_name = "Pyramid"; - val_vtk_type = 14; - break; - case MIXED: - elem_name = "Mixed"; - val_vtk_type = -1; - break; - default: - char buf[100]; - SPRINTF(buf, "Unsupported or unknown CGNS element type: (type %d)\n", val_elem_type); - SU2_MPI::Error(string(buf), CURRENT_FUNCTION); - break; - } - - return elem_name; -} #endif void CCGNSMeshReaderFVM::InitiateCommsAll(void* bufSend, const int* nElemSend, SU2_MPI::Request* sendReq, void* bufRecv, diff --git a/Common/src/geometry/meshreader/meson.build b/Common/src/geometry/meshreader/meson.build index fb44650ad56..f2ade5b4473 100644 --- a/Common/src/geometry/meshreader/meson.build +++ b/Common/src/geometry/meshreader/meson.build @@ -1,4 +1,5 @@ common_src += files(['CBoxMeshReaderFVM.cpp', + 'CCGNSMeshReaderBase.cpp', 'CCGNSMeshReaderFVM.cpp', 'CMeshReaderBase.cpp', 'CRectangularMeshReaderFVM.cpp', From 1108a49f1a2646bbd5f6da875639a3e38d22fa72 Mon Sep 17 00:00:00 2001 From: vdweide Date: Sat, 1 Feb 2025 18:12:56 +0100 Subject: [PATCH 04/15] Split the SU2 ASCII finite volume reader in a common base class and a class that is specific to the reading of the SU2 ASCII grid for the finite volume solver --- .../meshreader/CSU2ASCIIMeshReaderBase.hpp | 116 ++++ .../meshreader/CSU2ASCIIMeshReaderFVM.hpp | 68 +-- .../meshreader/CSU2ASCIIMeshReaderBase.cpp | 519 ++++++++++++++++++ .../meshreader/CSU2ASCIIMeshReaderFVM.cpp | 487 +--------------- Common/src/geometry/meshreader/meson.build | 1 + 5 files changed, 639 insertions(+), 552 deletions(-) create mode 100644 Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp create mode 100644 Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp new file mode 100644 index 00000000000..891141cf9ad --- /dev/null +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp @@ -0,0 +1,116 @@ +/*! + * \file CSU2ASCIIMeshReaderBase.hpp + * \brief Header file for the class CSU2ASCIIMeshReaderBase. + * The implementations are in the CSU2ASCIIMeshReaderBase.cpp file. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#include + +#include "CMeshReaderBase.hpp" + +/*! + * \class CSU2ASCIIMeshReaderBase + * \brief Base class for the reading of a native SU2 ASCII grid. + * \author T. Economon + */ +class CSU2ASCIIMeshReaderBase : public CMeshReaderBase { + protected: + enum class FileSection { POINTS, ELEMENTS, MARKERS }; /*!< \brief Different sections of the file. */ + std::array SectionOrder{}; /*!< \brief Order of the sections in the file. */ + + const unsigned short myZone; /*!< \brief Current SU2 zone index. */ + const unsigned short nZones; /*!< \brief Total number of zones in the SU2 file. */ + + const string meshFilename; /*!< \brief Name of the SU2 ASCII mesh file being read. */ + ifstream mesh_file; /*!< \brief File object for the SU2 ASCII mesh file. */ + + bool actuator_disk; /*!< \brief Boolean for whether we have an actuator disk to split. */ + + unsigned long ActDiskNewPoints = + 0; /*!< \brief Total number of new grid points to add due to actuator disk splitting. */ + + su2double Xloc = 0.0; /*!< \brief X-coordinate of the CG of the actuator disk surface. */ + su2double Yloc = 0.0; /*!< \brief X-coordinate of the CG of the actuator disk surface. */ + su2double Zloc = 0.0; /*!< \brief X-coordinate of the CG of the actuator disk surface. */ + + vector ActDisk_Bool; /*!< \brief Flag to identify the grid points on the actuator disk. */ + + vector ActDiskPoint_Back; /*!< \brief Vector containing the global index for the new grid points added + to the back of the actuator disk. */ + vector VolumePoint_Inv; /*!< \brief Vector containing the inverse mapping from the global index to the + added point index for the actuator disk. */ + + vector CoordXActDisk; /*!< \brief X-coordinates of the new grid points added by splitting the actuator disk + (size = ActDiskNewPoints). */ + vector CoordYActDisk; /*!< \brief Y-coordinates of the new grid points added by splitting the actuator disk + (size = ActDiskNewPoints). */ + vector CoordZActDisk; /*!< \brief Z-coordinates of the new grid points added by splitting the actuator disk + (size = ActDiskNewPoints). */ + + vector CoordXVolumePoint; /*!< \brief X-coordinates of the volume elements touching the actuator disk. */ + vector CoordYVolumePoint; /*!< \brief Y-coordinates of the volume elements touching the actuator disk. */ + vector CoordZVolumePoint; /*!< \brief Z-coordinates of the volume elements touching the actuator disk. */ + + /*! + * \brief Reads all SU2 ASCII mesh metadata and checks for errors. + * \param[in] single_pass - Try to read the contents together with the metadata if the order allows (points before + * elements). \param[in,out] config - Problem configuration where some metadata is updated (e.g. AoA). \returns True + * if single_pass was successful. + */ + bool ReadMetadata(const bool single_pass, CConfig* config); + + /*! + * \brief Reads the grid points from an SU2 zone into linear partitions across all ranks. + */ + void ReadPointCoordinates(const bool single_pass = false); + + /*! + * \brief Reads the interior volume elements from one section of an SU2 zone into linear partitions across all ranks. + */ + void ReadVolumeElementConnectivity(const bool single_pass = false); + + /*! + * \brief Reads the surface (boundary) elements from the SU2 zone. + */ + void ReadSurfaceElementConnectivity(const bool single_pass = false); + + /*! + * \brief Helper function to find the current zone in an SU2 ASCII mesh object. + */ + void FastForwardToMyZone(); + + public: + /*! + * \brief Constructor of the CSU2ASCIIMeshReaderBase class. + */ + CSU2ASCIIMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CSU2ASCIIMeshReaderBase class. + */ + virtual ~CSU2ASCIIMeshReaderBase(void) override; +}; diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp index 0222063fb56..10fada303d2 100644 --- a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp @@ -30,84 +30,20 @@ #include -#include "CMeshReaderBase.hpp" +#include "CSU2ASCIIMeshReaderBase.hpp" /*! * \class CSU2ASCIIMeshReaderFVM * \brief Reads a native SU2 ASCII grid into linear partitions for the finite volume solver (FVM). * \author T. Economon */ -class CSU2ASCIIMeshReaderFVM : public CMeshReaderBase { +class CSU2ASCIIMeshReaderFVM : public CSU2ASCIIMeshReaderBase { private: - enum class FileSection { POINTS, ELEMENTS, MARKERS }; /*!< \brief Different sections of the file. */ - std::array SectionOrder{}; /*!< \brief Order of the sections in the file. */ - - const unsigned short myZone; /*!< \brief Current SU2 zone index. */ - const unsigned short nZones; /*!< \brief Total number of zones in the SU2 file. */ - - const string meshFilename; /*!< \brief Name of the SU2 ASCII mesh file being read. */ - ifstream mesh_file; /*!< \brief File object for the SU2 ASCII mesh file. */ - - bool actuator_disk; /*!< \brief Boolean for whether we have an actuator disk to split. */ - - unsigned long ActDiskNewPoints = - 0; /*!< \brief Total number of new grid points to add due to actuator disk splitting. */ - - su2double Xloc = 0.0; /*!< \brief X-coordinate of the CG of the actuator disk surface. */ - su2double Yloc = 0.0; /*!< \brief X-coordinate of the CG of the actuator disk surface. */ - su2double Zloc = 0.0; /*!< \brief X-coordinate of the CG of the actuator disk surface. */ - - vector ActDisk_Bool; /*!< \brief Flag to identify the grid points on the actuator disk. */ - - vector ActDiskPoint_Back; /*!< \brief Vector containing the global index for the new grid points added - to the back of the actuator disk. */ - vector VolumePoint_Inv; /*!< \brief Vector containing the inverse mapping from the global index to the - added point index for the actuator disk. */ - - vector CoordXActDisk; /*!< \brief X-coordinates of the new grid points added by splitting the actuator disk - (size = ActDiskNewPoints). */ - vector CoordYActDisk; /*!< \brief Y-coordinates of the new grid points added by splitting the actuator disk - (size = ActDiskNewPoints). */ - vector CoordZActDisk; /*!< \brief Z-coordinates of the new grid points added by splitting the actuator disk - (size = ActDiskNewPoints). */ - - vector CoordXVolumePoint; /*!< \brief X-coordinates of the volume elements touching the actuator disk. */ - vector CoordYVolumePoint; /*!< \brief Y-coordinates of the volume elements touching the actuator disk. */ - vector CoordZVolumePoint; /*!< \brief Z-coordinates of the volume elements touching the actuator disk. */ - - /*! - * \brief Reads all SU2 ASCII mesh metadata and checks for errors. - * \param[in] single_pass - Try to read the contents together with the metadata if the order allows (points before - * elements). \param[in,out] config - Problem configuration where some metadata is updated (e.g. AoA). \returns True - * if single_pass was successful. - */ - bool ReadMetadata(const bool single_pass, CConfig* config); - /*! * \brief Splits a single surface actuator disk boundary into two separate markers (repeated points). */ void SplitActuatorDiskSurface(); - /*! - * \brief Reads the grid points from an SU2 zone into linear partitions across all ranks. - */ - void ReadPointCoordinates(const bool single_pass = false); - - /*! - * \brief Reads the interior volume elements from one section of an SU2 zone into linear partitions across all ranks. - */ - void ReadVolumeElementConnectivity(const bool single_pass = false); - - /*! - * \brief Reads the surface (boundary) elements from the SU2 zone. - */ - void ReadSurfaceElementConnectivity(const bool single_pass = false); - - /*! - * \brief Helper function to find the current zone in an SU2 ASCII mesh object. - */ - void FastForwardToMyZone(); - public: /*! * \brief Constructor of the CSU2ASCIIMeshReaderFVM class. diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp new file mode 100644 index 00000000000..845221356cb --- /dev/null +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp @@ -0,0 +1,519 @@ +/*! + * \file CSU2ASCIIMeshReaderBase.cpp + * \brief Helper class for the reading of a native SU2 ASCII grid file. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#include "../../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp" + +CSU2ASCIIMeshReaderBase::CSU2ASCIIMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) + : CMeshReaderBase(val_config, val_iZone, val_nZone), + myZone(val_iZone), + nZones(val_nZone), + meshFilename(config->GetMesh_FileName()) { +} + +CSU2ASCIIMeshReaderBase::~CSU2ASCIIMeshReaderBase(void) = default; + +bool CSU2ASCIIMeshReaderBase::ReadMetadata(const bool single_pass, CConfig* config) { + const bool harmonic_balance = config->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE; + const bool multizone_file = config->GetMultizone_Mesh(); + + /*--- Open grid file ---*/ + + mesh_file.open(meshFilename); + if (mesh_file.fail()) { + SU2_MPI::Error( + "Error opening SU2 ASCII grid.\n" + "Check that the file exists.", + CURRENT_FUNCTION); + } + + /*--- If more than one, find the curent zone in the mesh file. ---*/ + + string text_line; + if ((nZones > 1 && multizone_file) || harmonic_balance) { + if (harmonic_balance) { + if (rank == MASTER_NODE) cout << "Reading time instance " << config->GetiInst() + 1 << "." << endl; + } else { + bool foundZone = false; + while (getline(mesh_file, text_line)) { + /*--- Search for the current domain ---*/ + if (text_line.find("IZONE=", 0) != string::npos) { + text_line.erase(0, 6); + unsigned short jZone = atoi(text_line.c_str()); + if (jZone == myZone + 1) { + if (rank == MASTER_NODE) cout << "Reading zone " << myZone << " from native SU2 ASCII mesh." << endl; + foundZone = true; + break; + } + } + } + if (!foundZone) { + SU2_MPI::Error( + "Could not find the IZONE= keyword or the zone contents.\n" + "Check the SU2 ASCII file format.", + CURRENT_FUNCTION); + } + } + } + + /*--- Read the metadata: problem dimension, offsets for angle + of attack and angle of sideslip, global points, global elements, + and number of markers. Perform error checks as we go. ---*/ + + bool foundNDIME = false, foundNPOIN = false; + bool foundNELEM = false, foundNMARK = false; + + int current_section_idx = 0; + bool single_pass_active = false; + + while (getline(mesh_file, text_line)) { + /*--- Read the dimension of the problem ---*/ + + if (!foundNDIME && text_line.find("NDIME=", 0) != string::npos) { + text_line.erase(0, 6); + dimension = atoi(text_line.c_str()); + foundNDIME = true; + continue; + } + + /*--- The AoA and AoS offset values are optional. ---*/ + + if (text_line.find("AOA_OFFSET=", 0) != string::npos) { + text_line.erase(0, 11); + su2double AoA_Offset = atof(text_line.c_str()); + + /*--- The offset is in deg ---*/ + const su2double AoA_Current = config->GetAoA() + AoA_Offset; + config->SetAoA_Offset(AoA_Offset); + config->SetAoA(AoA_Current); + + if (AoA_Offset != 0.0) { + if (!config->GetDiscard_InFiles()) { + cout << "WARNING: AoA in the config file (" << config->GetAoA() << " deg.) +\n"; + cout << " AoA offset in mesh file (" << AoA_Offset << " deg.) = " << AoA_Current << " deg." << endl; + } else { + cout << "WARNING: Discarding the AoA offset in the mesh file." << endl; + } + } + continue; + } + + if (text_line.find("AOS_OFFSET=", 0) != string::npos) { + text_line.erase(0, 11); + su2double AoS_Offset = atof(text_line.c_str()); + + /*--- The offset is in deg ---*/ + const su2double AoS_Current = config->GetAoS() + AoS_Offset; + config->SetAoS_Offset(AoS_Offset); + config->SetAoS(AoS_Current); + + if (AoS_Offset != 0.0) { + if (!config->GetDiscard_InFiles()) { + cout << "WARNING: AoS in the config file (" << config->GetAoS() << " deg.) +\n"; + cout << " AoS offset in mesh file (" << AoS_Offset << " deg.) = " << AoS_Current << " deg." << endl; + } else { + cout << "WARNING: Discarding the AoS offset in the mesh file." << endl; + } + } + continue; + } + + if (!foundNPOIN && text_line.find("NPOIN=", 0) != string::npos) { + text_line.erase(0, 6); + numberOfGlobalPoints = atoi(text_line.c_str()); + + /* If the points were found first, read them, otherwise just consume the lines. */ + if (single_pass && foundNDIME && current_section_idx == 0) { + single_pass_active = true; + ReadPointCoordinates(true); + } else { + for (auto iPoint = 0ul; iPoint < numberOfGlobalPoints; iPoint++) getline(mesh_file, text_line); + } + SectionOrder[current_section_idx++] = FileSection::POINTS; + foundNPOIN = true; + continue; + } + + if (!foundNELEM && text_line.find("NELEM=", 0) != string::npos) { + text_line.erase(0, 6); + numberOfGlobalElements = atoi(text_line.c_str()); + + if (single_pass_active) { + ReadVolumeElementConnectivity(true); + } else { + for (auto iElem = 0ul; iElem < numberOfGlobalElements; iElem++) getline(mesh_file, text_line); + } + SectionOrder[current_section_idx++] = FileSection::ELEMENTS; + foundNELEM = true; + continue; + } + + if (!foundNMARK && text_line.find("NMARK=", 0) != string::npos) { + text_line.erase(0, 6); + numberOfMarkers = atoi(text_line.c_str()); + + if (current_section_idx != 2) { + SU2_MPI::Error("Markers must be listed after points and elements in the SU2 mesh file.", CURRENT_FUNCTION); + } + + if (single_pass_active) ReadSurfaceElementConnectivity(true); + + SectionOrder[current_section_idx++] = FileSection::MARKERS; + foundNMARK = true; + continue; + } + + /* Stop before we reach the next zone then check for errors below. */ + if (text_line.find("IZONE=", 0) != string::npos) { + break; + } + } + + mesh_file.close(); + + /* Throw an error if any of the keywords was not found. */ + if (!foundNDIME) { + SU2_MPI::Error( + "Could not find the keyword \"NDIME=\".\n" + "Check the SU2 ASCII file format.", + CURRENT_FUNCTION); + } + if (!foundNPOIN) { + SU2_MPI::Error( + "Could not find the keyword \"NPOIN=\".\n" + "Check the SU2 ASCII file format.", + CURRENT_FUNCTION); + } + if (!foundNELEM) { + SU2_MPI::Error( + "Could not find the keyword \"NELEM=\".\n" + "Check the SU2 ASCII file format.", + CURRENT_FUNCTION); + } + if (!foundNMARK) { + SU2_MPI::Error( + "Could not find the keyword \"NMARK=\".\n" + "Check the SU2 ASCII file format.", + CURRENT_FUNCTION); + } + + return single_pass_active; +} + +void CSU2ASCIIMeshReaderBase::ReadPointCoordinates(const bool single_pass) { + /* Get a partitioner to help with linear partitioning. */ + CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); + + /* Determine number of local points */ + numberOfLocalPoints = pointPartitioner.GetSizeOnRank(rank); + + /* Prepare our data structure for the point coordinates. */ + localPointCoordinates.resize(dimension); + for (int k = 0; k < dimension; k++) localPointCoordinates[k].reserve(numberOfLocalPoints); + + /*--- Read the point coordinates into our data structure. ---*/ + + while (true) { + string text_line; + if (!single_pass) { + getline(mesh_file, text_line); + if (text_line.find("NPOIN=", 0) == string::npos) continue; + } + + for (unsigned long GlobalIndex = 0; GlobalIndex < numberOfGlobalPoints; ++GlobalIndex) { + if (!actuator_disk) { + getline(mesh_file, text_line); + } else { + if (GlobalIndex < numberOfGlobalPoints - ActDiskNewPoints) { + getline(mesh_file, text_line); + } else { + /* This is a new actuator disk point, so we must construct a + string with the new point's coordinates. */ + ostringstream strsX, strsY, strsZ; + unsigned long BackActDisk_Index = GlobalIndex; + unsigned long LocalIndex = BackActDisk_Index - (numberOfGlobalPoints - ActDiskNewPoints); + strsX.precision(20); + strsY.precision(20); + strsZ.precision(20); + su2double CoordX = CoordXActDisk[LocalIndex]; + strsX << scientific << CoordX; + su2double CoordY = CoordYActDisk[LocalIndex]; + strsY << scientific << CoordY; + su2double CoordZ = CoordZActDisk[LocalIndex]; + strsZ << scientific << CoordZ; + text_line = strsX.str() + "\t" + strsY.str() + "\t" + strsZ.str(); + } + } + + /*--- We only read information for this node if it is owned by this + rank based upon our initial linear partitioning. ---*/ + + passivedouble Coords[3] = {0.0, 0.0, 0.0}; + if (pointPartitioner.IndexBelongsToRank(GlobalIndex, rank)) { + istringstream point_line(text_line); + + /* Store the coordinates more clearly. */ + point_line >> Coords[0]; + point_line >> Coords[1]; + if (dimension == 3) { + point_line >> Coords[2]; + } + + /* Load into the coordinate class data structure. */ + for (unsigned short iDim = 0; iDim < dimension; iDim++) { + localPointCoordinates[iDim].push_back(Coords[iDim]); + } + } + } + break; + } +} + +void CSU2ASCIIMeshReaderBase::ReadVolumeElementConnectivity(const bool single_pass) { + /* Get a partitioner to help with linear partitioning. */ + CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); + + /* Loop over our analytically defined of elements and store only those + that contain a node within our linear partition of points. */ + numberOfLocalElements = 0; + array connectivity{}; + + while (true) { + string text_line; + if (!single_pass) { + if (!getline(mesh_file, text_line)) break; + if (text_line.find("NELEM=", 0) == string::npos) continue; + } + + /*--- Loop over all the volumetric elements and store any element that + contains at least one of an owned node for this rank (i.e., there will + be element redundancy, since multiple ranks will store the same elems + on the boundaries of the initial linear partitioning. ---*/ + + numberOfLocalElements = 0; + + for (unsigned long GlobalIndex = 0; GlobalIndex < numberOfGlobalElements; ++GlobalIndex) { + getline(mesh_file, text_line); + istringstream elem_line(text_line); + + /*--- Decide whether this rank needs each element. ---*/ + + unsigned short VTK_Type; + elem_line >> VTK_Type; + + const auto nPointsElem = nPointsOfElementType(VTK_Type); + + for (unsigned short i = 0; i < nPointsElem; i++) { + elem_line >> connectivity[i]; + } + + if (actuator_disk) { + for (unsigned short i = 0; i < nPointsElem; i++) { + if (ActDisk_Bool[connectivity[i]]) { + su2double Xcg = 0.0; + unsigned long Counter = 0; + for (unsigned short j = 0; j < nPointsElem; j++) { + if (connectivity[j] < numberOfGlobalPoints - ActDiskNewPoints) { + Xcg += CoordXVolumePoint[VolumePoint_Inv[connectivity[j]]]; + Counter++; + } + } + Xcg = Xcg / su2double(Counter); + + if (Counter != 0 && Xcg > Xloc) { + connectivity[i] = ActDiskPoint_Back[connectivity[i]]; + } + } + } + } + + /* Check whether any of the points reside in our linear partition. */ + bool isOwned = false; + for (unsigned short i = 0; i < nPointsElem; i++) { + if (pointPartitioner.IndexBelongsToRank(connectivity[i], rank)) { + isOwned = true; + break; + } + } + + /* If element is owned, we need to store it locally. */ + if (isOwned) { + localVolumeElementConnectivity.push_back(GlobalIndex); + localVolumeElementConnectivity.push_back(VTK_Type); + /// TODO: Use a compressed format. + for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { + localVolumeElementConnectivity.push_back(connectivity[i]); + } + numberOfLocalElements++; + } + } + break; + } +} + +void CSU2ASCIIMeshReaderBase::ReadSurfaceElementConnectivity(const bool single_pass) { + /* We already read in the number of markers with the metadata. */ + surfaceElementConnectivity.resize(numberOfMarkers); + markerNames.resize(numberOfMarkers); + + array connectivity{}; + + /*--- In this routine, the boundary info is read by all ranks, + however, the surface connectivity is still handled by the + master node (and eventually distributed by the master as well). ---*/ + + while (true) { + string text_line; + if (!single_pass) { + if (!getline(mesh_file, text_line)) break; + if (text_line.find("NMARK=", 0) == string::npos) continue; + } + + for (unsigned short iMarker = 0; iMarker < numberOfMarkers; ++iMarker) { + getline(mesh_file, text_line); + text_line.erase(0, 11); + string::size_type position; + + for (unsigned short iChar = 0; iChar < 20; iChar++) { + position = text_line.find(' ', 0); + if (position != string::npos) text_line.erase(position, 1); + position = text_line.find('\r', 0); + if (position != string::npos) text_line.erase(position, 1); + position = text_line.find('\n', 0); + if (position != string::npos) text_line.erase(position, 1); + } + markerNames[iMarker] = text_line; + + bool duplicate = false; + if ((actuator_disk) && (markerNames[iMarker] == config->GetMarker_ActDiskInlet_TagBound(0))) { + duplicate = true; + markerNames[iMarker + 1] = config->GetMarker_ActDiskOutlet_TagBound(0); + } + + /*--- Physical boundaries definition ---*/ + + if (markerNames[iMarker] == "SEND_RECEIVE") { + /*--- Throw an error if we find deprecated references to SEND_RECEIVE + boundaries in the mesh. ---*/ + SU2_MPI::Error( + "Mesh file contains deprecated SEND_RECEIVE marker!\n" + "Please remove any SEND_RECEIVE markers from the SU2 ASCII mesh.", + CURRENT_FUNCTION); + } + + getline(mesh_file, text_line); + text_line.erase(0, 13); + unsigned long nElem_Bound = atoi(text_line.c_str()); + + /*--- Allocate space for elements ---*/ + + for (unsigned long iElem_Bound = 0; iElem_Bound < nElem_Bound; iElem_Bound++) { + getline(mesh_file, text_line); + istringstream bound_line(text_line); + + unsigned short VTK_Type; + bound_line >> VTK_Type; + + const auto nPointsElem = nPointsOfElementType(VTK_Type); + + if (dimension == 3 && VTK_Type == LINE) { + SU2_MPI::Error( + "Line boundary conditions are not possible for 3D calculations.\n" + "Please check the SU2 ASCII mesh file.", + CURRENT_FUNCTION); + } + + for (unsigned short i = 0; i < nPointsElem; i++) { + bound_line >> connectivity[i]; + } + + surfaceElementConnectivity[iMarker].push_back(0); + surfaceElementConnectivity[iMarker].push_back(VTK_Type); + for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { + surfaceElementConnectivity[iMarker].push_back(connectivity[i]); + } + + if (duplicate) { + for (unsigned short i = 0; i < nPointsElem; i++) { + if (ActDisk_Bool[connectivity[i]]) { + connectivity[i] = ActDiskPoint_Back[connectivity[i]]; + } + } + surfaceElementConnectivity[iMarker + 1].push_back(0); + surfaceElementConnectivity[iMarker + 1].push_back(VTK_Type); + for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { + surfaceElementConnectivity[iMarker + 1].push_back(connectivity[i]); + } + } + } + /*--- Increment the counter an extra time if we stored a duplicate. ---*/ + iMarker += duplicate; + } + break; + } + + if (rank != MASTER_NODE) return; + + /*--- Final error check for deprecated periodic BC format. ---*/ + + string text_line; + while (getline(mesh_file, text_line)) { + /*--- Find any periodic transformation information. ---*/ + + if (text_line.find("NPERIODIC=", 0) != string::npos) { + /*--- Read and store the number of transformations. ---*/ + text_line.erase(0, 10); + unsigned short nPeriodic = atoi(text_line.c_str()); + if (nPeriodic - 1 != 0) { + SU2_MPI::Error( + "Mesh file contains deprecated periodic format!\n\n" + "For SU2 v7.0.0 and later, preprocessing of periodic grids by SU2_MSH\n" + "is no longer necessary. Please use the original mesh file (prior to SU2_MSH)\n" + "with the same MARKER_PERIODIC definition in the configuration file.", + CURRENT_FUNCTION); + } + } + + /*--- Stop before we reach the next zone. ---*/ + if (text_line.find("IZONE=", 0) != string::npos) break; + } +} + +void CSU2ASCIIMeshReaderBase::FastForwardToMyZone() { + /*--- If more than one, fast-forward to my zone in the mesh file. ---*/ + + if (nZones == 1 || !config->GetMultizone_Mesh()) return; + + string text_line; + while (getline(mesh_file, text_line)) { + /*--- Search for the current domain ---*/ + if (text_line.find("IZONE=", 0) == string::npos) continue; + text_line.erase(0, 6); + unsigned short jZone = atoi(text_line.c_str()); + if (jZone == myZone + 1) break; + } +} diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp index 00307a90d94..96a30abb5e0 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp @@ -26,14 +26,10 @@ * License along with SU2. If not, see . */ -#include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) - : CMeshReaderBase(val_config, val_iZone, val_nZone), - myZone(val_iZone), - nZones(val_nZone), - meshFilename(config->GetMesh_FileName()) { + : CSU2ASCIIMeshReaderBase(val_config, val_iZone, val_nZone) { actuator_disk = (((config->GetnMarker_ActDiskInlet() != 0) || (config->GetnMarker_ActDiskOutlet() != 0)) && ((config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD) || ((config->GetKind_SU2() == SU2_COMPONENT::SU2_DEF) && (config->GetActDisk_SU2_DEF())))); @@ -75,193 +71,6 @@ CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned sho mesh_file.close(); } -bool CSU2ASCIIMeshReaderFVM::ReadMetadata(const bool single_pass, CConfig* config) { - const bool harmonic_balance = config->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE; - const bool multizone_file = config->GetMultizone_Mesh(); - - /*--- Open grid file ---*/ - - mesh_file.open(meshFilename); - if (mesh_file.fail()) { - SU2_MPI::Error( - "Error opening SU2 ASCII grid.\n" - "Check that the file exists.", - CURRENT_FUNCTION); - } - - /*--- If more than one, find the curent zone in the mesh file. ---*/ - - string text_line; - if ((nZones > 1 && multizone_file) || harmonic_balance) { - if (harmonic_balance) { - if (rank == MASTER_NODE) cout << "Reading time instance " << config->GetiInst() + 1 << "." << endl; - } else { - bool foundZone = false; - while (getline(mesh_file, text_line)) { - /*--- Search for the current domain ---*/ - if (text_line.find("IZONE=", 0) != string::npos) { - text_line.erase(0, 6); - unsigned short jZone = atoi(text_line.c_str()); - if (jZone == myZone + 1) { - if (rank == MASTER_NODE) cout << "Reading zone " << myZone << " from native SU2 ASCII mesh." << endl; - foundZone = true; - break; - } - } - } - if (!foundZone) { - SU2_MPI::Error( - "Could not find the IZONE= keyword or the zone contents.\n" - "Check the SU2 ASCII file format.", - CURRENT_FUNCTION); - } - } - } - - /*--- Read the metadata: problem dimension, offsets for angle - of attack and angle of sideslip, global points, global elements, - and number of markers. Perform error checks as we go. ---*/ - - bool foundNDIME = false, foundNPOIN = false; - bool foundNELEM = false, foundNMARK = false; - - int current_section_idx = 0; - bool single_pass_active = false; - - while (getline(mesh_file, text_line)) { - /*--- Read the dimension of the problem ---*/ - - if (!foundNDIME && text_line.find("NDIME=", 0) != string::npos) { - text_line.erase(0, 6); - dimension = atoi(text_line.c_str()); - foundNDIME = true; - continue; - } - - /*--- The AoA and AoS offset values are optional. ---*/ - - if (text_line.find("AOA_OFFSET=", 0) != string::npos) { - text_line.erase(0, 11); - su2double AoA_Offset = atof(text_line.c_str()); - - /*--- The offset is in deg ---*/ - const su2double AoA_Current = config->GetAoA() + AoA_Offset; - config->SetAoA_Offset(AoA_Offset); - config->SetAoA(AoA_Current); - - if (AoA_Offset != 0.0) { - if (!config->GetDiscard_InFiles()) { - cout << "WARNING: AoA in the config file (" << config->GetAoA() << " deg.) +\n"; - cout << " AoA offset in mesh file (" << AoA_Offset << " deg.) = " << AoA_Current << " deg." << endl; - } else { - cout << "WARNING: Discarding the AoA offset in the mesh file." << endl; - } - } - continue; - } - - if (text_line.find("AOS_OFFSET=", 0) != string::npos) { - text_line.erase(0, 11); - su2double AoS_Offset = atof(text_line.c_str()); - - /*--- The offset is in deg ---*/ - const su2double AoS_Current = config->GetAoS() + AoS_Offset; - config->SetAoS_Offset(AoS_Offset); - config->SetAoS(AoS_Current); - - if (AoS_Offset != 0.0) { - if (!config->GetDiscard_InFiles()) { - cout << "WARNING: AoS in the config file (" << config->GetAoS() << " deg.) +\n"; - cout << " AoS offset in mesh file (" << AoS_Offset << " deg.) = " << AoS_Current << " deg." << endl; - } else { - cout << "WARNING: Discarding the AoS offset in the mesh file." << endl; - } - } - continue; - } - - if (!foundNPOIN && text_line.find("NPOIN=", 0) != string::npos) { - text_line.erase(0, 6); - numberOfGlobalPoints = atoi(text_line.c_str()); - - /* If the points were found first, read them, otherwise just consume the lines. */ - if (single_pass && foundNDIME && current_section_idx == 0) { - single_pass_active = true; - ReadPointCoordinates(true); - } else { - for (auto iPoint = 0ul; iPoint < numberOfGlobalPoints; iPoint++) getline(mesh_file, text_line); - } - SectionOrder[current_section_idx++] = FileSection::POINTS; - foundNPOIN = true; - continue; - } - - if (!foundNELEM && text_line.find("NELEM=", 0) != string::npos) { - text_line.erase(0, 6); - numberOfGlobalElements = atoi(text_line.c_str()); - - if (single_pass_active) { - ReadVolumeElementConnectivity(true); - } else { - for (auto iElem = 0ul; iElem < numberOfGlobalElements; iElem++) getline(mesh_file, text_line); - } - SectionOrder[current_section_idx++] = FileSection::ELEMENTS; - foundNELEM = true; - continue; - } - - if (!foundNMARK && text_line.find("NMARK=", 0) != string::npos) { - text_line.erase(0, 6); - numberOfMarkers = atoi(text_line.c_str()); - - if (current_section_idx != 2) { - SU2_MPI::Error("Markers must be listed after points and elements in the SU2 mesh file.", CURRENT_FUNCTION); - } - - if (single_pass_active) ReadSurfaceElementConnectivity(true); - - SectionOrder[current_section_idx++] = FileSection::MARKERS; - foundNMARK = true; - continue; - } - - /* Stop before we reach the next zone then check for errors below. */ - if (text_line.find("IZONE=", 0) != string::npos) { - break; - } - } - - mesh_file.close(); - - /* Throw an error if any of the keywords was not found. */ - if (!foundNDIME) { - SU2_MPI::Error( - "Could not find the keyword \"NDIME=\".\n" - "Check the SU2 ASCII file format.", - CURRENT_FUNCTION); - } - if (!foundNPOIN) { - SU2_MPI::Error( - "Could not find the keyword \"NPOIN=\".\n" - "Check the SU2 ASCII file format.", - CURRENT_FUNCTION); - } - if (!foundNELEM) { - SU2_MPI::Error( - "Could not find the keyword \"NELEM=\".\n" - "Check the SU2 ASCII file format.", - CURRENT_FUNCTION); - } - if (!foundNMARK) { - SU2_MPI::Error( - "Could not find the keyword \"NMARK=\".\n" - "Check the SU2 ASCII file format.", - CURRENT_FUNCTION); - } - - return single_pass_active; -} - void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { /*--- Actuator disk preprocesing ---*/ @@ -783,297 +592,3 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { mesh_file.close(); } - -void CSU2ASCIIMeshReaderFVM::ReadPointCoordinates(const bool single_pass) { - /* Get a partitioner to help with linear partitioning. */ - CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); - - /* Determine number of local points */ - numberOfLocalPoints = pointPartitioner.GetSizeOnRank(rank); - - /* Prepare our data structure for the point coordinates. */ - localPointCoordinates.resize(dimension); - for (int k = 0; k < dimension; k++) localPointCoordinates[k].reserve(numberOfLocalPoints); - - /*--- Read the point coordinates into our data structure. ---*/ - - while (true) { - string text_line; - if (!single_pass) { - getline(mesh_file, text_line); - if (text_line.find("NPOIN=", 0) == string::npos) continue; - } - - for (unsigned long GlobalIndex = 0; GlobalIndex < numberOfGlobalPoints; ++GlobalIndex) { - if (!actuator_disk) { - getline(mesh_file, text_line); - } else { - if (GlobalIndex < numberOfGlobalPoints - ActDiskNewPoints) { - getline(mesh_file, text_line); - } else { - /* This is a new actuator disk point, so we must construct a - string with the new point's coordinates. */ - ostringstream strsX, strsY, strsZ; - unsigned long BackActDisk_Index = GlobalIndex; - unsigned long LocalIndex = BackActDisk_Index - (numberOfGlobalPoints - ActDiskNewPoints); - strsX.precision(20); - strsY.precision(20); - strsZ.precision(20); - su2double CoordX = CoordXActDisk[LocalIndex]; - strsX << scientific << CoordX; - su2double CoordY = CoordYActDisk[LocalIndex]; - strsY << scientific << CoordY; - su2double CoordZ = CoordZActDisk[LocalIndex]; - strsZ << scientific << CoordZ; - text_line = strsX.str() + "\t" + strsY.str() + "\t" + strsZ.str(); - } - } - - /*--- We only read information for this node if it is owned by this - rank based upon our initial linear partitioning. ---*/ - - passivedouble Coords[3] = {0.0, 0.0, 0.0}; - if (pointPartitioner.IndexBelongsToRank(GlobalIndex, rank)) { - istringstream point_line(text_line); - - /* Store the coordinates more clearly. */ - point_line >> Coords[0]; - point_line >> Coords[1]; - if (dimension == 3) { - point_line >> Coords[2]; - } - - /* Load into the coordinate class data structure. */ - for (unsigned short iDim = 0; iDim < dimension; iDim++) { - localPointCoordinates[iDim].push_back(Coords[iDim]); - } - } - } - break; - } -} - -void CSU2ASCIIMeshReaderFVM::ReadVolumeElementConnectivity(const bool single_pass) { - /* Get a partitioner to help with linear partitioning. */ - CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); - - /* Loop over our analytically defined of elements and store only those - that contain a node within our linear partition of points. */ - numberOfLocalElements = 0; - array connectivity{}; - - while (true) { - string text_line; - if (!single_pass) { - if (!getline(mesh_file, text_line)) break; - if (text_line.find("NELEM=", 0) == string::npos) continue; - } - - /*--- Loop over all the volumetric elements and store any element that - contains at least one of an owned node for this rank (i.e., there will - be element redundancy, since multiple ranks will store the same elems - on the boundaries of the initial linear partitioning. ---*/ - - numberOfLocalElements = 0; - - for (unsigned long GlobalIndex = 0; GlobalIndex < numberOfGlobalElements; ++GlobalIndex) { - getline(mesh_file, text_line); - istringstream elem_line(text_line); - - /*--- Decide whether this rank needs each element. ---*/ - - unsigned short VTK_Type; - elem_line >> VTK_Type; - - const auto nPointsElem = nPointsOfElementType(VTK_Type); - - for (unsigned short i = 0; i < nPointsElem; i++) { - elem_line >> connectivity[i]; - } - - if (actuator_disk) { - for (unsigned short i = 0; i < nPointsElem; i++) { - if (ActDisk_Bool[connectivity[i]]) { - su2double Xcg = 0.0; - unsigned long Counter = 0; - for (unsigned short j = 0; j < nPointsElem; j++) { - if (connectivity[j] < numberOfGlobalPoints - ActDiskNewPoints) { - Xcg += CoordXVolumePoint[VolumePoint_Inv[connectivity[j]]]; - Counter++; - } - } - Xcg = Xcg / su2double(Counter); - - if (Counter != 0 && Xcg > Xloc) { - connectivity[i] = ActDiskPoint_Back[connectivity[i]]; - } - } - } - } - - /* Check whether any of the points reside in our linear partition. */ - bool isOwned = false; - for (unsigned short i = 0; i < nPointsElem; i++) { - if (pointPartitioner.IndexBelongsToRank(connectivity[i], rank)) { - isOwned = true; - break; - } - } - - /* If element is owned, we need to store it locally. */ - if (isOwned) { - localVolumeElementConnectivity.push_back(GlobalIndex); - localVolumeElementConnectivity.push_back(VTK_Type); - /// TODO: Use a compressed format. - for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { - localVolumeElementConnectivity.push_back(connectivity[i]); - } - numberOfLocalElements++; - } - } - break; - } -} - -void CSU2ASCIIMeshReaderFVM::ReadSurfaceElementConnectivity(const bool single_pass) { - /* We already read in the number of markers with the metadata. */ - surfaceElementConnectivity.resize(numberOfMarkers); - markerNames.resize(numberOfMarkers); - - array connectivity{}; - - /*--- In this routine, the boundary info is read by all ranks, - however, the surface connectivity is still handled by the - master node (and eventually distributed by the master as well). ---*/ - - while (true) { - string text_line; - if (!single_pass) { - if (!getline(mesh_file, text_line)) break; - if (text_line.find("NMARK=", 0) == string::npos) continue; - } - - for (unsigned short iMarker = 0; iMarker < numberOfMarkers; ++iMarker) { - getline(mesh_file, text_line); - text_line.erase(0, 11); - string::size_type position; - - for (unsigned short iChar = 0; iChar < 20; iChar++) { - position = text_line.find(' ', 0); - if (position != string::npos) text_line.erase(position, 1); - position = text_line.find('\r', 0); - if (position != string::npos) text_line.erase(position, 1); - position = text_line.find('\n', 0); - if (position != string::npos) text_line.erase(position, 1); - } - markerNames[iMarker] = text_line; - - bool duplicate = false; - if ((actuator_disk) && (markerNames[iMarker] == config->GetMarker_ActDiskInlet_TagBound(0))) { - duplicate = true; - markerNames[iMarker + 1] = config->GetMarker_ActDiskOutlet_TagBound(0); - } - - /*--- Physical boundaries definition ---*/ - - if (markerNames[iMarker] == "SEND_RECEIVE") { - /*--- Throw an error if we find deprecated references to SEND_RECEIVE - boundaries in the mesh. ---*/ - SU2_MPI::Error( - "Mesh file contains deprecated SEND_RECEIVE marker!\n" - "Please remove any SEND_RECEIVE markers from the SU2 ASCII mesh.", - CURRENT_FUNCTION); - } - - getline(mesh_file, text_line); - text_line.erase(0, 13); - unsigned long nElem_Bound = atoi(text_line.c_str()); - - /*--- Allocate space for elements ---*/ - - for (unsigned long iElem_Bound = 0; iElem_Bound < nElem_Bound; iElem_Bound++) { - getline(mesh_file, text_line); - istringstream bound_line(text_line); - - unsigned short VTK_Type; - bound_line >> VTK_Type; - - const auto nPointsElem = nPointsOfElementType(VTK_Type); - - if (dimension == 3 && VTK_Type == LINE) { - SU2_MPI::Error( - "Line boundary conditions are not possible for 3D calculations.\n" - "Please check the SU2 ASCII mesh file.", - CURRENT_FUNCTION); - } - - for (unsigned short i = 0; i < nPointsElem; i++) { - bound_line >> connectivity[i]; - } - - surfaceElementConnectivity[iMarker].push_back(0); - surfaceElementConnectivity[iMarker].push_back(VTK_Type); - for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { - surfaceElementConnectivity[iMarker].push_back(connectivity[i]); - } - - if (duplicate) { - for (unsigned short i = 0; i < nPointsElem; i++) { - if (ActDisk_Bool[connectivity[i]]) { - connectivity[i] = ActDiskPoint_Back[connectivity[i]]; - } - } - surfaceElementConnectivity[iMarker + 1].push_back(0); - surfaceElementConnectivity[iMarker + 1].push_back(VTK_Type); - for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { - surfaceElementConnectivity[iMarker + 1].push_back(connectivity[i]); - } - } - } - /*--- Increment the counter an extra time if we stored a duplicate. ---*/ - iMarker += duplicate; - } - break; - } - - if (rank != MASTER_NODE) return; - - /*--- Final error check for deprecated periodic BC format. ---*/ - - string text_line; - while (getline(mesh_file, text_line)) { - /*--- Find any periodic transformation information. ---*/ - - if (text_line.find("NPERIODIC=", 0) != string::npos) { - /*--- Read and store the number of transformations. ---*/ - text_line.erase(0, 10); - unsigned short nPeriodic = atoi(text_line.c_str()); - if (nPeriodic - 1 != 0) { - SU2_MPI::Error( - "Mesh file contains deprecated periodic format!\n\n" - "For SU2 v7.0.0 and later, preprocessing of periodic grids by SU2_MSH\n" - "is no longer necessary. Please use the original mesh file (prior to SU2_MSH)\n" - "with the same MARKER_PERIODIC definition in the configuration file.", - CURRENT_FUNCTION); - } - } - - /*--- Stop before we reach the next zone. ---*/ - if (text_line.find("IZONE=", 0) != string::npos) break; - } -} - -void CSU2ASCIIMeshReaderFVM::FastForwardToMyZone() { - /*--- If more than one, fast-forward to my zone in the mesh file. ---*/ - - if (nZones == 1 || !config->GetMultizone_Mesh()) return; - - string text_line; - while (getline(mesh_file, text_line)) { - /*--- Search for the current domain ---*/ - if (text_line.find("IZONE=", 0) == string::npos) continue; - text_line.erase(0, 6); - unsigned short jZone = atoi(text_line.c_str()); - if (jZone == myZone + 1) break; - } -} diff --git a/Common/src/geometry/meshreader/meson.build b/Common/src/geometry/meshreader/meson.build index f2ade5b4473..789dc1edf84 100644 --- a/Common/src/geometry/meshreader/meson.build +++ b/Common/src/geometry/meshreader/meson.build @@ -3,4 +3,5 @@ common_src += files(['CBoxMeshReaderFVM.cpp', 'CCGNSMeshReaderFVM.cpp', 'CMeshReaderBase.cpp', 'CRectangularMeshReaderFVM.cpp', + 'CSU2ASCIIMeshReaderBase.cpp', 'CSU2ASCIIMeshReaderFVM.cpp']) From 844d5316f5bb848d9e17eae955ecb870c0b7ed16 Mon Sep 17 00:00:00 2001 From: vdweide Date: Mon, 3 Feb 2025 10:05:28 +0100 Subject: [PATCH 05/15] The reading of CGNS files for the FEM solver done via the meshreader classes --- Common/include/fem/fem_cgns_elements.hpp | 198 --- Common/include/fem/fem_geometry_structure.hpp | 3 - Common/include/geometry/CPhysicalGeometry.hpp | 11 - .../geometry/meshreader/CCGNSElementType.hpp | 425 +++++ .../meshreader/CCGNSMeshReaderFEM.hpp | 100 ++ .../meshreader/CCGNSMeshReaderFVM.hpp | 4 +- .../geometry/meshreader/CMeshReaderBase.hpp | 40 +- Common/src/fem/fem_cgns_elements.cpp | 1578 ----------------- .../src/fem/geometry_structure_fem_part.cpp | 1064 ----------- Common/src/fem/meson.build | 3 +- Common/src/geometry/CPhysicalGeometry.cpp | 4 +- .../geometry/meshreader/CCGNSElementType.cpp | 840 +++++++++ .../meshreader/CCGNSMeshReaderFEM.cpp | 550 ++++++ .../geometry/meshreader/CMeshReaderBase.cpp | 70 + Common/src/geometry/meshreader/meson.build | 2 + 15 files changed, 2032 insertions(+), 2860 deletions(-) delete mode 100644 Common/include/fem/fem_cgns_elements.hpp create mode 100644 Common/include/geometry/meshreader/CCGNSElementType.hpp create mode 100644 Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp delete mode 100644 Common/src/fem/fem_cgns_elements.cpp create mode 100644 Common/src/geometry/meshreader/CCGNSElementType.cpp create mode 100644 Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp diff --git a/Common/include/fem/fem_cgns_elements.hpp b/Common/include/fem/fem_cgns_elements.hpp deleted file mode 100644 index f3debaeb0ea..00000000000 --- a/Common/include/fem/fem_cgns_elements.hpp +++ /dev/null @@ -1,198 +0,0 @@ -/*! - * \file fem_cgns_elements.hpp - * \brief Headers of the classes and functions for reading CGNS files - * with high order elements. - * The functions are in the cgns_elements.cpp file. - * \author E. van der Weide - * \version 8.1.0 "Harrier" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 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. - * - * SU2 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 SU2. If not, see . - */ - -#pragma once - -#include "../parallelization/mpi_structure.hpp" - -#ifdef HAVE_CGNS -#include "cgnslib.h" -#endif - -#include "../geometry/primal_grid/CPrimalGridFEM.hpp" - -/* Forward declaration of CBoundaryFace to avoid problems. */ -class CBoundaryFace; - -#ifdef HAVE_CGNS -#if CGNS_VERSION >= 3300 - -/*! - * \class CCGNSElementType - * \brief Class which stores the CGNS element type info for a connectivity section. - */ - -class CCGNSElementType { - public: - int connID; /*!< \brief CGNS connectivity ID of this connectivity. */ - ElementType_t elemType; /*!< \brief Element type according to the CGNS convention, - possibly MIXED. */ - cgsize_t indBeg; /*!< \brief Index of the first element in the CGNS connectivity. */ - cgsize_t indEnd; /*!< \brief Index of the last element in the CGNS connectivity. */ - cgsize_t nElem; /*!< \brief Number of elements present for this element type. */ - - std::string connName; /*!< \brief Name of this connectivity. */ - - bool volumeConn; /*!< \brief Whether or not this is a volume connectivity. */ - bool surfaceConn; /*!< \brief Whether or not this is a surface connectivity. */ - - /* Standard constructor, nothing to be done. */ - CCGNSElementType() {} - - /* Destructor, nothing to be done. */ - ~CCGNSElementType() {} - - /*--- Member function, which determines the meta data for this element type. ---*/ - void DetermineMetaData(const unsigned short nDim, const int fn, const int iBase, const int iZone, const int iConn); - - /*--- Member function, which reads the required boundary connectivity range. ---*/ - void ReadBoundaryConnectivityRange(const int fn, const int iBase, const int iZone, const unsigned long offsetRank, - const unsigned long nBoundElemRank, const unsigned long startingBoundElemIDRank, - unsigned long& locBoundElemCount, std::vector& boundElems); - - /*--- Member function, which reads the required connectivity range. ---*/ - void ReadConnectivityRange(const int fn, const int iBase, const int iZone, const unsigned long offsetRank, - const unsigned long nElemRank, const unsigned long startingElemIDRank, CPrimalGrid**& elem, - unsigned long& locElemCount, unsigned long& nDOFsLoc); - - private: - /*--- Member function, which creates the required data for the given - element type. ---*/ - void CreateDataElementType(const ElementType_t typeElem, unsigned short& VTK_Type, unsigned short& nPoly, - unsigned short& nDOFs, std::vector& SU2ToCGNS); - - /*--- Member function, which determines the element dimension, i.e. the - number of parametric coordinates. ---*/ - unsigned short DetermineElementDimension(const int fn, const int iBase, const int iZone); - - /*--- Member function, which determines the element dimension when the - connectivity is mixed. ---*/ - unsigned short DetermineElementDimensionMixed(const int fn, const int iBase, const int iZone); - - /*--- Member function, which determines the corresponding index of the - given element in the stored types. If not present, a new index - is created. ---*/ - unsigned short IndexInStoredTypes(const ElementType_t typeElem, std::vector& CGNS_Type, - std::vector& VTK_Type, std::vector& nPoly, - std::vector& nDOFs, - std::vector >& SU2ToCGNS); - - /*--- Functions to create the conversion data from CGNS format to SU2 format - for all the supported CGNS elements. ---*/ - void CreateDataNODE(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataBAR_2(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataBAR_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataBAR_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataBAR_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTRI_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTRI_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTRI_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTRI_15(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataQUAD_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataQUAD_9(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataQUAD_16(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataQUAD_25(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTETRA_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTETRA_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTETRA_20(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataTETRA_35(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPYRA_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPYRA_14(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPYRA_30(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPYRA_55(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPENTA_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPENTA_18(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPENTA_40(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataPENTA_75(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataHEXA_8(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataHEXA_27(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataHEXA_64(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); - - void CreateDataHEXA_125(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - std::vector& SU2ToCGNS); -}; -#endif -#endif - -using namespace std; diff --git a/Common/include/fem/fem_geometry_structure.hpp b/Common/include/fem/fem_geometry_structure.hpp index 4d3e9cc367d..ab4cc457f40 100644 --- a/Common/include/fem/fem_geometry_structure.hpp +++ b/Common/include/fem/fem_geometry_structure.hpp @@ -30,9 +30,6 @@ #include "../geometry/CGeometry.hpp" #include "fem_standard_element.hpp" -#ifdef HAVE_CGNS -#include "fem_cgns_elements.hpp" -#endif #include "../wall_model.hpp" #include "../linear_algebra/blas_structure.hpp" diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index a474dcbddd6..b20b2991566 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -299,17 +299,6 @@ class CPhysicalGeometry final : public CGeometry { void Read_SU2_Format_Parallel_FEM(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone); - /*! - * \brief Reads for the FEM solver the geometry of the grid and adjust the boundary - * conditions with the configuration file in parallel (for parmetis). - * \param[in] config - Definition of the particular problem. - * \param[in] val_mesh_filename - Name of the file with the grid information. - * \param[in] val_iZone - Domain to be read from the grid file. - * \param[in] val_nZone - Total number of domains in the grid file. - */ - void Read_CGNS_Format_Parallel_FEM(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, - unsigned short val_nZone); - /*! * \brief Routine to load the CGNS grid points from a single zone into the proper SU2 data structures. * \param[in] config - definition of the particular problem. diff --git a/Common/include/geometry/meshreader/CCGNSElementType.hpp b/Common/include/geometry/meshreader/CCGNSElementType.hpp new file mode 100644 index 00000000000..e081347be1b --- /dev/null +++ b/Common/include/geometry/meshreader/CCGNSElementType.hpp @@ -0,0 +1,425 @@ +/*! + * \file CCGNSElementType.hpp + * \brief Header file for the class CCGNSElementType. + * The implementations are in the CCGNSElementType.cpp file. + * \author E. van der Weide + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#include + +#ifdef HAVE_CGNS +#include "cgnslib.h" +#endif + +#ifdef HAVE_CGNS + +using namespace std; + +/*! + * \class CCGNSElementType + * \brief Class used to convert the CGNS format to SU2 format for high order elements. +* \author: E. van der Weide + */ +class CCGNSElementType { +private: + + vector CGNSTypeStored; /*!< \brief CGNS element types for which the data is stored. */ + vector VTKTypeStored; /*!< \brief VTK type of the element. */ + vector nPolyStored; /*!< \brief Polynomial degree of the element. */ + vector nDOFsStored; /*!< \brief Number of DOFs of the element. */ + vector > SU2ToCGNSStored; /*!< \brief Double vector, which stores the conversion + from SU2 to CGNS for the type in local numbering. */ +public: + + /*--- Standard constructor, nothing to be done. ---*/ + CCGNSElementType() = default; + + /*--- Destructor, nothing to be done. ---*/ + ~CCGNSElementType() = default; + + /*! + * \brief Converts the connectivity information from CGNS to SU2 format. + * \param[in] val_elemType - CGNS elements type to be converted. + * \param[in] val_globalID - Global ID of this element. + * \param[in] connCGNS - Array with the connectivity of the element in CGNS format. + * \param[out] connSU2 - Vector with the connectivity and meta data in SU2 format. + */ + void CGNSToSU2(const ElementType_t val_elemType, + const unsigned long val_globalID, + const cgsize_t *connCGNS, + std::vector &connSU2); + +private: + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a node. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataNODE(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Bar2 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataBAR_2(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Bar3 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataBAR_3(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Bar4 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataBAR_4(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Bar5 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataBAR_5(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tri3 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTRI_3(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tri6 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTRI_6(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tri10 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTRI_10(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tri15 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTRI_15(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Quad4 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataQUAD_4(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Quad9 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataQUAD_9(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Quad16 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataQUAD_16(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Quad25 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataQUAD_25(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tetra4 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTETRA_4(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tetra10 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTETRA_10(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tetra20 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTETRA_20(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Tetra35 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataTETRA_35(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Pyra5 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPYRA_5(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Pyra14 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPYRA_14(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Pyra30 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPYRA_30(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Pyra55 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPYRA_55(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Penta6 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPENTA_6(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Penta18 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPENTA_18(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Penta40 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPENTA_40(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Penta75 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataPENTA_75(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Hexa8 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataHEXA_8(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Hexa27 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataHEXA_27(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Hexa64 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataHEXA_64(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); + + /*! + * \brief Converts the connectivity from CGNS to SU2 for a Hexa125 element. + * \param[out] VTK_Type - Corresponding VTK type + * \param[out] nPoly - Polynomial degree + * \param[out] nDOFs - Number of DOFs of the element. + * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. + */ + void CreateDataHEXA_125(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS); +}; +#endif diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp new file mode 100644 index 00000000000..dfd8aa7c680 --- /dev/null +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp @@ -0,0 +1,100 @@ +/*! + * \file CCGNSMeshReaderFEM.hpp + * \brief Header file for the class CCGNSMeshReaderFEM. + * The implementations are in the CCGNSMeshReaderFEM.cpp file. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#include "CCGNSMeshReaderBase.hpp" + +/*! + * \class CCGNSMeshReaderFEM + * \brief Reads a CGNS zone into linear partitions for the finite element solver (FEM). + * \author: T. Economon + */ +class CCGNSMeshReaderFEM final : public CCGNSMeshReaderBase { + private: + + /*! + * \brief Communicates the grid points to the MPI rank where they are needed. + */ + void CommPointCoordinates(); + +#ifdef HAVE_CGNS + + /*! + * \brief Reads the connectivity range from a CGNS section and convert it to the internal format. + * \param[in] val_section - CGNS section index. + * \param[in] val_firstIndex - Global index of the first element to be stored on this rank. + * \param[in] val_lastIndex - Global index of the last element (not included) to be stored on this rank. + * \param[inout] elemCount - Counter, which keeps track how many global elements are stored. + * \param[inout] localElemCount - Counter, which keeps track how many local elements are stored. + * \param[inout] localConn - Vector where the connectivity must be stored. + */ + void ReadCGNSConnectivityRangeSection(const int val_section, + const unsigned long val_firstIndex, + const unsigned long val_lastIndex, + unsigned long &elemCount, + unsigned long &localElemCount, + vector &localConn); + +/*! + * \brief Reads the interior volume elements from one section of a CGNS zone into linear partitions across all ranks. + */ + void ReadCGNSVolumeElementConnectivity(); + + /*! + * \brief Reads the surface (boundary) elements from one section of a CGNS zone into linear partitions across all ranks. + */ + void ReadCGNSSurfaceElementConnectivity(); + + /*! + * \brief Reads the connectivity from a CGNS surface section and select the relevant faces. + * \param[in] val_section - CGNS section index. + * \param[in] localFaces - The faces of the locally stored volume elements. + * \param[out] nSurfElem - Number of local surface elements stored for this surface section. + * \param[out] surfConn - Vector to store the connectivity of the surface elements to be stored. + */ + void ReadCGNSSurfaceSection(const int val_section, + const vector &localFaces, + unsigned long &nSurfElem, + vector &surfConn); +#endif + + public: + + /*! + * \brief Constructor of the CCGNSMeshReaderFEM class. + */ + CCGNSMeshReaderFEM(CConfig *val_config, + unsigned short val_iZone, + unsigned short val_nZone); + + /*! + * \brief Destructor of the CCGNSMeshReaderFEM class. + */ + ~CCGNSMeshReaderFEM(void); +}; diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp index 4edb6cbf27c..8e7770c973a 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp @@ -35,7 +35,7 @@ * \brief Reads a CGNS zone into linear partitions for the finite volume solver (FVM). * \author: T. Economon */ -class CCGNSMeshReaderFVM : public CCGNSMeshReaderBase { +class CCGNSMeshReaderFVM final : public CCGNSMeshReaderBase { private: #ifdef HAVE_CGNS /*! @@ -96,5 +96,5 @@ class CCGNSMeshReaderFVM : public CCGNSMeshReaderBase { /*! * \brief Destructor of the CCGNSMeshReaderFVM class. */ - ~CCGNSMeshReaderFVM(void) override; + ~CCGNSMeshReaderFVM(void); }; diff --git a/Common/include/geometry/meshreader/CMeshReaderBase.hpp b/Common/include/geometry/meshreader/CMeshReaderBase.hpp index 6b81a4a16f8..da3f72c48cc 100644 --- a/Common/include/geometry/meshreader/CMeshReaderBase.hpp +++ b/Common/include/geometry/meshreader/CMeshReaderBase.hpp @@ -31,6 +31,8 @@ #include +#include "../primal_grid/CPrimalGridFEM.hpp" +#include "../../fem/geometry_structure_fem_part.hpp" #include "../../parallelization/mpi_structure.hpp" #include "../../CConfig.hpp" @@ -54,6 +56,7 @@ class CMeshReaderBase { vector > localPointCoordinates; /*!< \brief Vector holding the coordinates from the mesh file for the local grid points. First index is dimension, second is point index. */ + vector globalPointIDs; /*!< \brief Vector holding the global IDs of the local grid points. */ unsigned long numberOfLocalElements = 0; /*!< \brief Number of local elements within the linear partition on this rank. */ @@ -63,9 +66,28 @@ class CMeshReaderBase { unsigned long numberOfMarkers = 0; /*!< \brief Total number of markers contained within the mesh file. */ vector markerNames; /*!< \brief String names for all markers in the mesh file. */ + vector numberOfLocalSurfaceElements; /*!< \brief Vector containing the number of local surface elements. */ vector > surfaceElementConnectivity; /*!< \brief Vector containing the surface element connectivity from the mesh file on a - per-marker basis. Only the master node reads and stores this connectivity. */ + per-marker basis. For FVM, only the master node reads and stores this connectivity. */ + + /*! + * \brief Function, which determines the faces of the local volume elements. + * \param[out] localFaces - The faces of the locally stored volume elements. + */ + void DetermineFacesVolumeElements(vector &localFaces); + + /*! + * \brief Get all the corner points of all the faces of the given element. It must + * \param[in] elemInfo - Array, which contains the info of the given element. + * \param[out] nFaces - Number of faces of the element. + * \param[out] nPointsPerFace - Number of corner points for each of the faces. + * \param[out] faceConn - Global IDs of the corner points of the faces. + */ + void GetCornerPointsAllFaces(const unsigned long *elemInfo, + unsigned short &numFaces, + unsigned short nPointsPerFace[], + unsigned long faceConn[6][4]); public: /*! @@ -84,6 +106,14 @@ class CMeshReaderBase { */ inline unsigned short GetDimension() const { return dimension; } + /*! + * \brief Get the global IDs of the local points. + * \returns Reference to the vector containing the global points IDs. + */ + inline const vector &GetGlobalPointIDs() const { + return globalPointIDs; + } + /*! * \brief Get the local point coordinates (linearly partitioned). * \returns Local point coordinates (linear partitioned). @@ -99,6 +129,14 @@ class CMeshReaderBase { return surfaceElementConnectivity[val_iMarker]; } + /*! + * \brief Get the number surface elements for all markers. + * \returns Reference to the vector containing the number of surface elements for all markers. + */ + inline const vector &GetNumberOfSurfaceElementsAllMarkers() const { + return numberOfLocalSurfaceElements; + } + /*! * \brief Get the number surface elements for the specified marker. * \param[in] val_iMarker - current marker index. diff --git a/Common/src/fem/fem_cgns_elements.cpp b/Common/src/fem/fem_cgns_elements.cpp deleted file mode 100644 index e4df7f0393b..00000000000 --- a/Common/src/fem/fem_cgns_elements.cpp +++ /dev/null @@ -1,1578 +0,0 @@ -/*! - * \file fem_cgns_elements.cpp - * \brief CGNS element definitions and conversions to the SU2 standard. - * \author E. van der Weide - * \version 8.1.0 "Harrier" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) - * - * SU2 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. - * - * SU2 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 SU2. If not, see . - */ - -#ifdef HAVE_CGNS -#include "../../include/fem/fem_cgns_elements.hpp" -#include "../../include/fem/geometry_structure_fem_part.hpp" -#include "../../include/parallelization/mpi_structure.hpp" - -#include -#include -#include - -using namespace std; - -#if CGNS_VERSION >= 3300 - -void CCGNSElementType::DetermineMetaData(const unsigned short nDim, const int fn, const int iBase, const int iZone, - const int iConn) { - /* Store the connectivity ID. */ - connID = iConn; - - /* Read the element type and range from the CGNS file. */ - char cgnsname[CGNS_STRING_SIZE]; - int nBndry, parentFlag; - if (cg_section_read(fn, iBase, iZone, iConn, cgnsname, &elemType, &indBeg, &indEnd, &nBndry, &parentFlag) != CG_OK) - cg_error_exit(); - - /* Store the name of this connectivity. */ - connName = cgnsname; - - /* Determine the number of elements present in this connectivity section. */ - nElem = indEnd - indBeg + 1; - - /* Determine the dimension of this element type, i.e. the number of - parametric coordinates and conclude whether or not this is a volume or - surface connectivity. Note that it is possible that it is neither of these, - e.g. line elements for 3D. This information is not needed for the DG - flow solver and is therefore ignored. */ - const unsigned short nDimElem = DetermineElementDimension(fn, iBase, iZone); - volumeConn = (nDimElem == nDim); - surfaceConn = (nDimElem == nDim - 1); -} - -void CCGNSElementType::ReadBoundaryConnectivityRange(const int fn, const int iBase, const int iZone, - const unsigned long offsetRank, const unsigned long nBoundElemRank, - const unsigned long startingBoundElemIDRank, - unsigned long& locBoundElemCount, - vector& boundElems) { - /* Determine the index range to be read for this rank. */ - const cgsize_t iBeg = indBeg + offsetRank; - const cgsize_t iEnd = iBeg + nBoundElemRank - 1; - - /* Determine the size of the vector needed to read the connectivity - data from the CGNS file. */ - cgsize_t sizeNeeded; - if (cg_ElementPartialSize(fn, iBase, iZone, connID, iBeg, iEnd, &sizeNeeded) != CG_OK) cg_error_exit(); - - /* Allocate the memory for the connectivity and read the data. */ - vector connCGNSVec(sizeNeeded); - if (elemType == MIXED) { - vector connCGNSOffsetVec(iEnd - iBeg + 2); - if (cg_poly_elements_partial_read(fn, iBase, iZone, connID, iBeg, iEnd, connCGNSVec.data(), - connCGNSOffsetVec.data(), nullptr) != CG_OK) - cg_error_exit(); - } else { - if (cg_elements_partial_read(fn, iBase, iZone, connID, iBeg, iEnd, connCGNSVec.data(), nullptr) != CG_OK) - cg_error_exit(); - } - - /* Define the variables needed to convert the connectivities from CGNS to - SU2 format. Note that the vectors are needed to support a connectivity - section with mixed element types. */ - vector CGNS_Type; - vector VTK_Type; - vector nPoly; - vector nDOFs; - - vector > SU2ToCGNS; - - /* Definition of variables used in the loop below. */ - cgsize_t* connCGNS = connCGNSVec.data(); - ElementType_t typeElem = elemType; - vector connSU2; - - /* Loop over the elements just read. */ - for (unsigned long i = 0; i < nBoundElemRank; ++i, ++locBoundElemCount) { - /* Determine the element type for this element if this is a mixed - connectivity and set the pointer to the actual connectivity data. */ - if (elemType == MIXED) { - typeElem = (ElementType_t)connCGNS[0]; - ++connCGNS; - } - - /* Determine the index in the stored vectors (CGNS_Type, VTK_Type, etc), - which corresponds to this element. If the type is not stored yet, - a new entry in these vectors will be created. */ - const unsigned short ind = IndexInStoredTypes(typeElem, CGNS_Type, VTK_Type, nPoly, nDOFs, SU2ToCGNS); - - /* Resize the connSU2 vector to the appropriate size. */ - connSU2.resize(nDOFs[ind]); - - /* Create the connectivity used in SU2 by carrying out the renumbering. - Note that in CGNS the numbering starts at 1, while in SU2 it starts - at 0. This explains the addition of -1. */ - for (unsigned short j = 0; j < nDOFs[ind]; ++j) connSU2[j] = connCGNS[SU2ToCGNS[ind][j]] - 1; - - /* Set the pointer for connCGNS for the data of the next element. */ - connCGNS += nDOFs[ind]; - - /* Determine the global boundary element ID of this element. */ - const unsigned long globBoundElemID = startingBoundElemIDRank + locBoundElemCount; - - /* Create an object of CBoundaryFace and store it in boundElems. - Note that the corresponding domain element is not known yet and - is therefore set to ULONG_MAX. */ - CBoundaryFace thisBoundFace; - thisBoundFace.VTK_Type = VTK_Type[ind]; - thisBoundFace.nPolyGrid = nPoly[ind]; - thisBoundFace.nDOFsGrid = nDOFs[ind]; - thisBoundFace.globalBoundElemID = globBoundElemID; - thisBoundFace.domainElementID = ULONG_MAX; - thisBoundFace.Nodes = connSU2; - - boundElems.push_back(thisBoundFace); - } -} - -void CCGNSElementType::ReadConnectivityRange(const int fn, const int iBase, const int iZone, - const unsigned long offsetRank, const unsigned long nElemRank, - const unsigned long startingElemIDRank, CPrimalGrid**& elem, - unsigned long& locElemCount, unsigned long& nDOFsLoc) { - /* Determine the index range to be read for this rank. */ - const cgsize_t iBeg = indBeg + offsetRank; - const cgsize_t iEnd = iBeg + nElemRank - 1; - - /* Determine the size of the vector needed to read the connectivity - data from the CGNS file. */ - cgsize_t sizeNeeded; - if (cg_ElementPartialSize(fn, iBase, iZone, connID, iBeg, iEnd, &sizeNeeded) != CG_OK) cg_error_exit(); - - /* Allocate the memory for the connectivity and read the data. */ - vector connCGNSVec(sizeNeeded); - if (elemType == MIXED) { - vector connCGNSOffsetVec(iEnd - iBeg + 2); - if (cg_poly_elements_partial_read(fn, iBase, iZone, connID, iBeg, iEnd, connCGNSVec.data(), - connCGNSOffsetVec.data(), nullptr) != CG_OK) - cg_error_exit(); - - } else { - if (cg_elements_partial_read(fn, iBase, iZone, connID, iBeg, iEnd, connCGNSVec.data(), nullptr) != CG_OK) - cg_error_exit(); - } - - /* Define the variables needed to convert the connectivities from CGNS to - SU2 format. Note that the vectors are needed to support a connectivity - section with mixed element types. */ - vector CGNS_Type; - vector VTK_Type; - vector nPoly; - vector nDOFs; - - vector > SU2ToCGNS; - - /* Definition of variables used in the loop below. */ - cgsize_t* connCGNS = connCGNSVec.data(); - ElementType_t typeElem = elemType; - vector connSU2; - - /* Loop over the elements just read. */ - for (unsigned long i = 0; i < nElemRank; ++i, ++locElemCount) { - /* Determine the element type for this element if this is a mixed - connectivity and set the pointer to the actual connectivity data. */ - if (elemType == MIXED) { - typeElem = (ElementType_t)connCGNS[0]; - ++connCGNS; - } - - /* Determine the index in the stored vectors (CGNS_Type, VTK_Type, etc), - which corresponds to this element. If the type is not stored yet, - a new entry in these vectors will be created. */ - const unsigned short ind = IndexInStoredTypes(typeElem, CGNS_Type, VTK_Type, nPoly, nDOFs, SU2ToCGNS); - - /* Resize the connSU2 vector to the appropriate size. */ - connSU2.resize(nDOFs[ind]); - - /* Create the connectivity used in SU2 by carrying out the renumbering. - Note that in CGNS the numbering starts at 1, while in SU2 it starts - at 0. This explains the addition of -1. */ - for (unsigned short j = 0; j < nDOFs[ind]; ++j) connSU2[j] = connCGNS[SU2ToCGNS[ind][j]] - 1; - - /* Set the pointer for connCGNS for the data of the next element. */ - connCGNS += nDOFs[ind]; - - /* Determine the global element ID of this element. */ - const unsigned long globElemID = startingElemIDRank + locElemCount; - - /* Create a new FEM primal grid element, which stores the required - information. Note that the second to last argument contains the local - offset of the DOFs. This will be corrected to the global offset - afterwards in CPhysicalGeometry::Read_CGNS_Format_Parallel_FEM. - Also note that in CGNS it is not possible (at least at the moment) - to specify a different polynomial degree for the grid and solution. */ - elem[locElemCount] = new CPrimalGridFEM(globElemID, VTK_Type[ind], nPoly[ind], nPoly[ind], nDOFs[ind], nDOFs[ind], - nDOFsLoc, connSU2.data()); - - /* Update the counter nDOFsLoc. */ - nDOFsLoc += nDOFs[ind]; - } -} - -unsigned short CCGNSElementType::DetermineElementDimension(const int fn, const int iBase, const int iZone) { - /*--- Determine the element type and return the appropriate element - dimension, i.e. the number of parametric coordinates needed to - describe the element. ---*/ - switch (elemType) { - case NODE: - return 0; - - case BAR_2: - case BAR_3: - case BAR_4: - case BAR_5: - return 1; - - case TRI_3: - case TRI_6: - case TRI_9: - case TRI_10: - case TRI_12: - case TRI_15: - case QUAD_4: - case QUAD_8: - case QUAD_9: - case QUAD_12: - case QUAD_16: - case QUAD_P4_16: - case QUAD_25: - return 2; - - case TETRA_4: - case TETRA_10: - case TETRA_16: - case TETRA_20: - case TETRA_22: - case TETRA_34: - case TETRA_35: - case PYRA_5: - case PYRA_14: - case PYRA_13: - case PYRA_21: - case PYRA_29: - case PYRA_30: - case PYRA_P4_29: - case PYRA_50: - case PYRA_55: - case PENTA_6: - case PENTA_15: - case PENTA_18: - case PENTA_24: - case PENTA_38: - case PENTA_40: - case PENTA_33: - case PENTA_66: - case PENTA_75: - case HEXA_8: - case HEXA_20: - case HEXA_27: - case HEXA_32: - case HEXA_56: - case HEXA_64: - case HEXA_44: - case HEXA_98: - case HEXA_125: - return 3; - - case MIXED: - return DetermineElementDimensionMixed(fn, iBase, iZone); - - default: - ostringstream message; - message << "Unsupported CGNS element type, " << elemType << ", encountered."; - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - /* Just return a value to avoid a compiler warning. The program should - never reach this position. */ - return 0; -} - -unsigned short CCGNSElementType::DetermineElementDimensionMixed(const int fn, const int iBase, const int iZone) { - /* Determine the required size of the vector to read the - data of the first element of this connectivity. */ - cgsize_t sizeNeeded; - if (cg_ElementPartialSize(fn, iBase, iZone, connID, indBeg, indBeg, &sizeNeeded) != CG_OK) cg_error_exit(); - - /* Read the data of the first element in this section. */ - vector buf(sizeNeeded); - vector buf_offset(2, 0); - if (cg_poly_elements_partial_read(fn, iBase, iZone, connID, indBeg, indBeg, buf.data(), buf_offset.data(), nullptr) != - CG_OK) - cg_error_exit(); - - /* The first entry of buf contains the element type. Copy this value - temporarily into the member variable elemType and determine the - element dimension of this element. */ - elemType = (ElementType_t)buf[0]; - - unsigned short nDimElem = DetermineElementDimension(fn, iBase, iZone); - - /* Reset the element type to MIXED and return the element dimension. */ - elemType = MIXED; - return nDimElem; -} - -unsigned short CCGNSElementType::IndexInStoredTypes(const ElementType_t typeElem, vector& CGNS_Type, - vector& VTK_Type, vector& nPoly, - vector& nDOFs, - vector >& SU2ToCGNS) { - /* Loop over the available types and check if the current type is present. - If so, break the loop, such that the correct index is stored. */ - unsigned short ind; - for (ind = 0; ind < CGNS_Type.size(); ++ind) - if (typeElem == CGNS_Type[ind]) break; - - /* If the current element type is not present yet, the data for this - type must be created. */ - if (ind == CGNS_Type.size()) { - unsigned short VTKElem, nPolyElem, nDOFsElem; - vector SU2ToCGNSElem; - CreateDataElementType(typeElem, VTKElem, nPolyElem, nDOFsElem, SU2ToCGNSElem); - - CGNS_Type.push_back(typeElem); - VTK_Type.push_back(VTKElem); - nPoly.push_back(nPolyElem); - nDOFs.push_back(nDOFsElem); - SU2ToCGNS.push_back(SU2ToCGNSElem); - } - - /* Return the index. */ - return ind; -} - -void CCGNSElementType::CreateDataElementType(const ElementType_t typeElem, unsigned short& VTK_Type, - unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /*--- Determine the element type and call the corresponding function - to determine the actual data. ---*/ - switch (typeElem) { - case NODE: - CreateDataNODE(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case BAR_2: - CreateDataBAR_2(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case BAR_3: - CreateDataBAR_3(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case BAR_4: - CreateDataBAR_4(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case BAR_5: - CreateDataBAR_5(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TRI_3: - CreateDataTRI_3(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TRI_6: - CreateDataTRI_6(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TRI_10: - CreateDataTRI_10(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TRI_15: - CreateDataTRI_15(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case QUAD_4: - CreateDataQUAD_4(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case QUAD_9: - CreateDataQUAD_9(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case QUAD_16: - CreateDataQUAD_16(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case QUAD_25: - CreateDataQUAD_25(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TETRA_4: - CreateDataTETRA_4(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TETRA_10: - CreateDataTETRA_10(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TETRA_20: - CreateDataTETRA_20(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case TETRA_35: - CreateDataTETRA_35(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PYRA_5: - CreateDataPYRA_5(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PYRA_14: - CreateDataPYRA_14(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PYRA_30: - CreateDataPYRA_30(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PYRA_55: - CreateDataPYRA_55(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PENTA_6: - CreateDataPENTA_6(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PENTA_18: - CreateDataPENTA_18(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PENTA_40: - CreateDataPENTA_40(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case PENTA_75: - CreateDataPENTA_75(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case HEXA_8: - CreateDataHEXA_8(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case HEXA_27: - CreateDataHEXA_27(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case HEXA_64: - CreateDataHEXA_64(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - case HEXA_125: - CreateDataHEXA_125(VTK_Type, nPoly, nDOFs, SU2ToCGNS); - break; - - default: - /* Print an error message that this element type is not supported and exit. */ - ostringstream message; - message << "CGNS element type " << typeElem << " not supported."; - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } -} - -/*------------------------------------------------------------------------*/ -/*--- Below this line there are only the conversion routines between ---*/ -/*--- CGNS and SU2 format for the specific elements. ---*/ -/*------------------------------------------------------------------------*/ - -void CCGNSElementType::CreateDataNODE(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* Set the required data for a NODE. */ - VTK_Type = VERTEX; - nPoly = 0; - nDOFs = 1; - SU2ToCGNS.push_back(0); -} - -void CCGNSElementType::CreateDataBAR_2(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The BAR_2 element is a linear element. The numbering of the nodes is - the same for CGNS and SU2. */ - VTK_Type = LINE; - nPoly = 1; - nDOFs = 2; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; -} - -void CCGNSElementType::CreateDataBAR_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The BAR_3 element is a quadratic element. SU2 numbers to nodes with - increasing parametric value, while in CGNS the internal node is - numbered last. */ - VTK_Type = LINE; - nPoly = 2; - nDOFs = 3; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 2; - SU2ToCGNS[2] = 1; -} - -void CCGNSElementType::CreateDataBAR_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The BAR_4 element is a cubic element. SU2 numbers to nodes with - increasing parametric value, while in CGNS the internal nodes are - numbered last. */ - VTK_Type = LINE; - nPoly = 3; - nDOFs = 4; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 2; - SU2ToCGNS[2] = 3; - SU2ToCGNS[3] = 1; -} - -void CCGNSElementType::CreateDataBAR_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The BAR_5 element is a quartic element. SU2 numbers to nodes with - increasing parametric value, while in CGNS the internal nodes are - numbered last. */ - VTK_Type = LINE; - nPoly = 4; - nDOFs = 5; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 2; - SU2ToCGNS[2] = 3; - SU2ToCGNS[3] = 4; - SU2ToCGNS[4] = 1; -} - -void CCGNSElementType::CreateDataTRI_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TRI_3 element is a linear triangle. The node numbering is the same - in SU2 and CGNS. */ - VTK_Type = TRIANGLE; - nPoly = 1; - nDOFs = 3; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; - SU2ToCGNS[2] = 2; -} - -void CCGNSElementType::CreateDataTRI_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TRI_6 element is a quadratic triangle. In CGNS the nodes are numbered - as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes (not present for TRI_6). - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. */ - VTK_Type = TRIANGLE; - nPoly = 2; - nDOFs = 6; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 3; - SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 5; - SU2ToCGNS[4] = 4; - SU2ToCGNS[5] = 2; -} - -void CCGNSElementType::CreateDataTRI_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TRI_10 element is a cubic triangle. In CGNS the nodes are numbered - as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. */ - VTK_Type = TRIANGLE; - nPoly = 3; - nDOFs = 10; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 3; - SU2ToCGNS[2] = 4; - SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 8; - SU2ToCGNS[5] = 9; - SU2ToCGNS[6] = 5; - SU2ToCGNS[7] = 7; - SU2ToCGNS[8] = 6; - SU2ToCGNS[9] = 2; -} - -void CCGNSElementType::CreateDataTRI_15(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TRI_15 element is a quartic triangle. In CGNS the nodes are numbered - as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. - Also note that in the CGNS standard the face nodes are not placed at - the location for uniform spacing. This effect is currently ignored, - i.e. it is assumed that the spacing in parameter space is uniform. */ - VTK_Type = TRIANGLE; - nPoly = 4; - nDOFs = 15; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 3; - SU2ToCGNS[2] = 4; - SU2ToCGNS[3] = 5; - SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 11; - SU2ToCGNS[6] = 12; - SU2ToCGNS[7] = 13; - SU2ToCGNS[8] = 6; - SU2ToCGNS[9] = 10; - SU2ToCGNS[10] = 14; - SU2ToCGNS[11] = 7; - SU2ToCGNS[12] = 9; - SU2ToCGNS[13] = 8; - SU2ToCGNS[14] = 2; -} - -void CCGNSElementType::CreateDataQUAD_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The QUAD_4 element is a linear quadrilateral. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes (not present for QUAD_4). - - Third the face nodes (not present for QUAD_4). - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. */ - VTK_Type = QUADRILATERAL; - nPoly = 1; - nDOFs = 4; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; - SU2ToCGNS[2] = 3; - SU2ToCGNS[3] = 2; -} - -void CCGNSElementType::CreateDataQUAD_9(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The QUAD_9 element is a quadratic quadrilateral. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. */ - VTK_Type = QUADRILATERAL; - nPoly = 2; - nDOFs = 9; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 4; - SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 7; - SU2ToCGNS[4] = 8; - SU2ToCGNS[5] = 5; - SU2ToCGNS[6] = 3; - SU2ToCGNS[7] = 6; - SU2ToCGNS[8] = 2; -} - -void CCGNSElementType::CreateDataQUAD_16(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The QUAD_16 element is a cubic quadrilateral. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. */ - VTK_Type = QUADRILATERAL; - nPoly = 3; - nDOFs = 16; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 4; - SU2ToCGNS[2] = 5; - SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 11; - SU2ToCGNS[5] = 12; - SU2ToCGNS[6] = 13; - SU2ToCGNS[7] = 6; - SU2ToCGNS[8] = 10; - SU2ToCGNS[9] = 15; - SU2ToCGNS[10] = 14; - SU2ToCGNS[11] = 7; - SU2ToCGNS[12] = 3; - SU2ToCGNS[13] = 9; - SU2ToCGNS[14] = 8; - SU2ToCGNS[15] = 2; -} - -void CCGNSElementType::CreateDataQUAD_25(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The QUAD_25 element is a quartic quadrilateral. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - In SU2 the node numbering takes place along increasing i- and j-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the other edge. */ - VTK_Type = QUADRILATERAL; - nPoly = 4; - nDOFs = 25; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 4; - SU2ToCGNS[2] = 5; - SU2ToCGNS[3] = 6; - SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 15; - SU2ToCGNS[6] = 16; - SU2ToCGNS[7] = 17; - SU2ToCGNS[8] = 18; - SU2ToCGNS[9] = 7; - SU2ToCGNS[10] = 14; - SU2ToCGNS[11] = 23; - SU2ToCGNS[12] = 24; - SU2ToCGNS[13] = 19; - SU2ToCGNS[14] = 8; - SU2ToCGNS[15] = 13; - SU2ToCGNS[16] = 22; - SU2ToCGNS[17] = 21; - SU2ToCGNS[18] = 20; - SU2ToCGNS[19] = 9; - SU2ToCGNS[20] = 3; - SU2ToCGNS[21] = 12; - SU2ToCGNS[22] = 11; - SU2ToCGNS[23] = 10; - SU2ToCGNS[24] = 2; -} - -void CCGNSElementType::CreateDataTETRA_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TETRA_4 element is a linear tetrahedron. The node numbering is - the same in SU2 and CGNS. */ - VTK_Type = TETRAHEDRON; - nPoly = 1; - nDOFs = 4; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; - SU2ToCGNS[2] = 2; - SU2ToCGNS[3] = 3; -} - -void CCGNSElementType::CreateDataTETRA_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TETRA_10 element is a quadratic tetrahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes (not present in TETRA_10). - - Fourth the volume nodes (not present in TETRA_10). - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = TETRAHEDRON; - nPoly = 2; - nDOFs = 10; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 4; - SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 6; - SU2ToCGNS[4] = 5; - SU2ToCGNS[5] = 2; - SU2ToCGNS[6] = 7; - SU2ToCGNS[7] = 8; - SU2ToCGNS[8] = 9; - SU2ToCGNS[9] = 3; -} - -void CCGNSElementType::CreateDataTETRA_20(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TETRA_20 element is a cubic tetrahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes (not present in TETRA_20). - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = TETRAHEDRON; - nPoly = 3; - nDOFs = 20; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 4; - SU2ToCGNS[2] = 5; - SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 9; - SU2ToCGNS[5] = 16; - SU2ToCGNS[6] = 6; - SU2ToCGNS[7] = 8; - SU2ToCGNS[8] = 7; - SU2ToCGNS[9] = 2; - SU2ToCGNS[10] = 10; - SU2ToCGNS[11] = 17; - SU2ToCGNS[12] = 12; - SU2ToCGNS[13] = 19; - SU2ToCGNS[14] = 18; - SU2ToCGNS[15] = 14; - SU2ToCGNS[16] = 11; - SU2ToCGNS[17] = 13; - SU2ToCGNS[18] = 15; - SU2ToCGNS[19] = 3; -} - -void CCGNSElementType::CreateDataTETRA_35(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The TETRA_35 element is a quartic tetrahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. Also note that in the CGNS standard the face and volume - nodes are not placed at the location for uniform spacing. This effect is - currently ignored, i.e. it is assumed that the spacing in parameter space - is uniform. */ - VTK_Type = TETRAHEDRON; - nPoly = 4; - nDOFs = 35; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 4; - SU2ToCGNS[2] = 5; - SU2ToCGNS[3] = 6; - SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 12; - SU2ToCGNS[6] = 22; - SU2ToCGNS[7] = 23; - SU2ToCGNS[8] = 7; - SU2ToCGNS[9] = 11; - SU2ToCGNS[10] = 24; - SU2ToCGNS[11] = 8; - SU2ToCGNS[12] = 10; - SU2ToCGNS[13] = 9; - SU2ToCGNS[14] = 2; - SU2ToCGNS[15] = 13; - SU2ToCGNS[16] = 25; - SU2ToCGNS[17] = 26; - SU2ToCGNS[18] = 16; - SU2ToCGNS[19] = 32; - SU2ToCGNS[20] = 34; - SU2ToCGNS[21] = 28; - SU2ToCGNS[22] = 31; - SU2ToCGNS[23] = 29; - SU2ToCGNS[24] = 19; - SU2ToCGNS[25] = 14; - SU2ToCGNS[26] = 27; - SU2ToCGNS[27] = 17; - SU2ToCGNS[28] = 33; - SU2ToCGNS[29] = 30; - SU2ToCGNS[30] = 20; - SU2ToCGNS[31] = 15; - SU2ToCGNS[32] = 18; - SU2ToCGNS[33] = 21; - SU2ToCGNS[34] = 3; -} - -void CCGNSElementType::CreateDataPYRA_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PYRA_5 element is a linear pyramid. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes (not present in PYRA_5). - - Third the face nodes (not present in PYRA_5). - - Fourth the volume nodes (not present in PYRA_5). - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = PYRAMID; - nPoly = 1; - nDOFs = 5; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; - SU2ToCGNS[2] = 3; - SU2ToCGNS[3] = 2; - SU2ToCGNS[4] = 4; -} - -void CCGNSElementType::CreateDataPYRA_14(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PYRA_14 element is a quadratic pyramid. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes (not present in PYRA_14). - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = PYRAMID; - nPoly = 2; - nDOFs = 14; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 5; - SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 8; - SU2ToCGNS[4] = 13; - SU2ToCGNS[5] = 6; - SU2ToCGNS[6] = 3; - SU2ToCGNS[7] = 7; - SU2ToCGNS[8] = 2; - SU2ToCGNS[9] = 9; - SU2ToCGNS[10] = 10; - SU2ToCGNS[11] = 12; - SU2ToCGNS[12] = 11; - SU2ToCGNS[13] = 4; -} - -void CCGNSElementType::CreateDataPYRA_30(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PYRA_30 element is a cubic pyramid. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = PYRAMID; - nPoly = 3; - nDOFs = 30; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 5; - SU2ToCGNS[2] = 6; - SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 12; - SU2ToCGNS[5] = 21; - SU2ToCGNS[6] = 22; - SU2ToCGNS[7] = 7; - SU2ToCGNS[8] = 11; - SU2ToCGNS[9] = 24; - SU2ToCGNS[10] = 23; - SU2ToCGNS[11] = 8; - SU2ToCGNS[12] = 3; - SU2ToCGNS[13] = 20; - SU2ToCGNS[14] = 9; - SU2ToCGNS[15] = 3; - SU2ToCGNS[16] = 13; - SU2ToCGNS[17] = 25; - SU2ToCGNS[18] = 15; - SU2ToCGNS[19] = 28; - SU2ToCGNS[20] = 29; - SU2ToCGNS[21] = 26; - SU2ToCGNS[22] = 19; - SU2ToCGNS[23] = 27; - SU2ToCGNS[24] = 17; - SU2ToCGNS[25] = 14; - SU2ToCGNS[26] = 16; - SU2ToCGNS[27] = 20; - SU2ToCGNS[28] = 18; - SU2ToCGNS[29] = 4; -} - -void CCGNSElementType::CreateDataPYRA_55(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PYRA_55 element is a quartic pyramid. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. Also note that in the CGNS standard the triangular face - and volume nodes are not placed at the location for uniform spacing. This - effect is currently ignored, i.e. it is assumed that the spacing in - parameter space is uniform.*/ - VTK_Type = PYRAMID; - nPoly = 4; - nDOFs = 55; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 5; - SU2ToCGNS[2] = 6; - SU2ToCGNS[3] = 7; - SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 16; - SU2ToCGNS[6] = 29; - SU2ToCGNS[7] = 30; - SU2ToCGNS[8] = 31; - SU2ToCGNS[9] = 8; - SU2ToCGNS[10] = 15; - SU2ToCGNS[11] = 36; - SU2ToCGNS[12] = 37; - SU2ToCGNS[13] = 32; - SU2ToCGNS[14] = 9; - SU2ToCGNS[15] = 14; - SU2ToCGNS[16] = 35; - SU2ToCGNS[17] = 34; - SU2ToCGNS[18] = 33; - SU2ToCGNS[19] = 10; - SU2ToCGNS[20] = 3; - SU2ToCGNS[21] = 13; - SU2ToCGNS[22] = 12; - SU2ToCGNS[23] = 11; - SU2ToCGNS[24] = 2; - SU2ToCGNS[25] = 17; - SU2ToCGNS[26] = 38; - SU2ToCGNS[27] = 39; - SU2ToCGNS[28] = 20; - SU2ToCGNS[29] = 48; - SU2ToCGNS[30] = 50; - SU2ToCGNS[31] = 51; - SU2ToCGNS[32] = 41; - SU2ToCGNS[33] = 47; - SU2ToCGNS[34] = 53; - SU2ToCGNS[35] = 52; - SU2ToCGNS[36] = 42; - SU2ToCGNS[37] = 26; - SU2ToCGNS[38] = 45; - SU2ToCGNS[39] = 44; - SU2ToCGNS[40] = 23; - SU2ToCGNS[41] = 18; - SU2ToCGNS[42] = 40; - SU2ToCGNS[43] = 21; - SU2ToCGNS[44] = 49; - SU2ToCGNS[45] = 54; - SU2ToCGNS[46] = 43; - SU2ToCGNS[47] = 27; - SU2ToCGNS[48] = 46; - SU2ToCGNS[49] = 24; - SU2ToCGNS[50] = 19; - SU2ToCGNS[51] = 22; - SU2ToCGNS[52] = 28; - SU2ToCGNS[53] = 25; - SU2ToCGNS[54] = 4; -} - -void CCGNSElementType::CreateDataPENTA_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PENTA_6 element is a linear prism. The node numbering is - the same in SU2 and CGNS. */ - VTK_Type = PRISM; - nPoly = 1; - nDOFs = 6; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; - SU2ToCGNS[2] = 2; - SU2ToCGNS[3] = 3; - SU2ToCGNS[4] = 4; - SU2ToCGNS[5] = 5; -} - -void CCGNSElementType::CreateDataPENTA_18(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PENTA_18 element is a quadratic prism. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes (not present in PENTA_18). - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = PRISM; - nPoly = 2; - nDOFs = 18; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 6; - SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 8; - SU2ToCGNS[4] = 7; - SU2ToCGNS[5] = 2; - SU2ToCGNS[6] = 9; - SU2ToCGNS[7] = 15; - SU2ToCGNS[8] = 10; - SU2ToCGNS[9] = 17; - SU2ToCGNS[10] = 16; - SU2ToCGNS[11] = 11; - SU2ToCGNS[12] = 3; - SU2ToCGNS[13] = 12; - SU2ToCGNS[14] = 4; - SU2ToCGNS[15] = 14; - SU2ToCGNS[16] = 13; - SU2ToCGNS[17] = 5; -} - -void CCGNSElementType::CreateDataPENTA_40(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PENTA_40 element is a cubic prism. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = PRISM; - nPoly = 3; - nDOFs = 40; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 6; - SU2ToCGNS[2] = 7; - SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 11; - SU2ToCGNS[5] = 24; - SU2ToCGNS[6] = 8; - SU2ToCGNS[7] = 10; - SU2ToCGNS[8] = 9; - SU2ToCGNS[9] = 2; - SU2ToCGNS[10] = 12; - SU2ToCGNS[11] = 25; - SU2ToCGNS[12] = 26; - SU2ToCGNS[13] = 14; - SU2ToCGNS[14] = 34; - SU2ToCGNS[15] = 38; - SU2ToCGNS[16] = 29; - SU2ToCGNS[17] = 33; - SU2ToCGNS[18] = 30; - SU2ToCGNS[19] = 16; - SU2ToCGNS[20] = 13; - SU2ToCGNS[21] = 28; - SU2ToCGNS[22] = 27; - SU2ToCGNS[23] = 15; - SU2ToCGNS[24] = 35; - SU2ToCGNS[25] = 39; - SU2ToCGNS[26] = 32; - SU2ToCGNS[27] = 36; - SU2ToCGNS[28] = 31; - SU2ToCGNS[29] = 17; - SU2ToCGNS[30] = 3; - SU2ToCGNS[31] = 18; - SU2ToCGNS[32] = 19; - SU2ToCGNS[33] = 4; - SU2ToCGNS[34] = 23; - SU2ToCGNS[35] = 37; - SU2ToCGNS[36] = 20; - SU2ToCGNS[37] = 22; - SU2ToCGNS[38] = 21; - SU2ToCGNS[39] = 5; -} - -void CCGNSElementType::CreateDataPENTA_75(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The PENTA_75 element is a quartic prism. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. Also note that in the CGNS standard the triangular face - and volume nodes are not placed at the location for uniform spacing. This - effect is currently ignored, i.e. it is assumed that the spacing in - parameter space is uniform. */ - VTK_Type = PRISM; - nPoly = 4; - nDOFs = 75; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 6; - SU2ToCGNS[2] = 7; - SU2ToCGNS[3] = 8; - SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 14; - SU2ToCGNS[6] = 33; - SU2ToCGNS[7] = 34; - SU2ToCGNS[8] = 9; - SU2ToCGNS[9] = 13; - SU2ToCGNS[10] = 35; - SU2ToCGNS[11] = 10; - SU2ToCGNS[12] = 12; - SU2ToCGNS[13] = 11; - SU2ToCGNS[14] = 2; - SU2ToCGNS[15] = 15; - SU2ToCGNS[16] = 36; - SU2ToCGNS[17] = 37; - SU2ToCGNS[18] = 38; - SU2ToCGNS[19] = 18; - SU2ToCGNS[20] = 56; - SU2ToCGNS[21] = 66; - SU2ToCGNS[22] = 67; - SU2ToCGNS[23] = 45; - SU2ToCGNS[24] = 55; - SU2ToCGNS[25] = 68; - SU2ToCGNS[26] = 46; - SU2ToCGNS[27] = 54; - SU2ToCGNS[28] = 47; - SU2ToCGNS[29] = 21; - SU2ToCGNS[30] = 16; - SU2ToCGNS[31] = 43; - SU2ToCGNS[32] = 44; - SU2ToCGNS[33] = 39; - SU2ToCGNS[34] = 19; - SU2ToCGNS[35] = 57; - SU2ToCGNS[36] = 69; - SU2ToCGNS[37] = 70; - SU2ToCGNS[38] = 52; - SU2ToCGNS[39] = 62; - SU2ToCGNS[40] = 71; - SU2ToCGNS[41] = 53; - SU2ToCGNS[42] = 61; - SU2ToCGNS[43] = 48; - SU2ToCGNS[44] = 22; - SU2ToCGNS[45] = 17; - SU2ToCGNS[46] = 42; - SU2ToCGNS[47] = 41; - SU2ToCGNS[48] = 40; - SU2ToCGNS[49] = 20; - SU2ToCGNS[50] = 58; - SU2ToCGNS[51] = 72; - SU2ToCGNS[52] = 73; - SU2ToCGNS[53] = 51; - SU2ToCGNS[54] = 59; - SU2ToCGNS[55] = 74; - SU2ToCGNS[56] = 50; - SU2ToCGNS[57] = 60; - SU2ToCGNS[58] = 49; - SU2ToCGNS[59] = 23; - SU2ToCGNS[60] = 3; - SU2ToCGNS[61] = 24; - SU2ToCGNS[62] = 25; - SU2ToCGNS[63] = 26; - SU2ToCGNS[64] = 4; - SU2ToCGNS[65] = 32; - SU2ToCGNS[66] = 63; - SU2ToCGNS[67] = 64; - SU2ToCGNS[68] = 27; - SU2ToCGNS[69] = 31; - SU2ToCGNS[70] = 65; - SU2ToCGNS[71] = 28; - SU2ToCGNS[72] = 30; - SU2ToCGNS[73] = 29; - SU2ToCGNS[74] = 5; -} - -void CCGNSElementType::CreateDataHEXA_8(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The HEXA_8 element is a linear hexahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes (not present in HEXA_8). - - Third the face nodes (not present in HEXA_8). - - Fourth the volume nodes (not present in HEXA_8). - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = HEXAHEDRON; - nPoly = 1; - nDOFs = 8; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 1; - SU2ToCGNS[2] = 3; - SU2ToCGNS[3] = 2; - SU2ToCGNS[4] = 4; - SU2ToCGNS[5] = 5; - SU2ToCGNS[6] = 7; - SU2ToCGNS[7] = 6; -} - -void CCGNSElementType::CreateDataHEXA_27(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The HEXA_27 element is a quadratic hexahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = HEXAHEDRON; - nPoly = 2; - nDOFs = 27; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 8; - SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 11; - SU2ToCGNS[4] = 20; - SU2ToCGNS[5] = 9; - SU2ToCGNS[6] = 3; - SU2ToCGNS[7] = 10; - SU2ToCGNS[8] = 2; - SU2ToCGNS[9] = 12; - SU2ToCGNS[10] = 21; - SU2ToCGNS[11] = 13; - SU2ToCGNS[12] = 24; - SU2ToCGNS[13] = 26; - SU2ToCGNS[14] = 22; - SU2ToCGNS[15] = 15; - SU2ToCGNS[16] = 23; - SU2ToCGNS[17] = 14; - SU2ToCGNS[18] = 4; - SU2ToCGNS[19] = 16; - SU2ToCGNS[20] = 5; - SU2ToCGNS[21] = 19; - SU2ToCGNS[22] = 25; - SU2ToCGNS[23] = 17; - SU2ToCGNS[24] = 7; - SU2ToCGNS[25] = 18; - SU2ToCGNS[26] = 6; -} - -void CCGNSElementType::CreateDataHEXA_64(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The HEXA_64 element is a cubic hexahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = HEXAHEDRON; - nPoly = 3; - nDOFs = 64; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 8; - SU2ToCGNS[2] = 9; - SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 15; - SU2ToCGNS[5] = 32; - SU2ToCGNS[6] = 33; - SU2ToCGNS[7] = 10; - SU2ToCGNS[8] = 14; - SU2ToCGNS[9] = 35; - SU2ToCGNS[10] = 34; - SU2ToCGNS[11] = 11; - SU2ToCGNS[12] = 3; - SU2ToCGNS[13] = 13; - SU2ToCGNS[14] = 12; - SU2ToCGNS[15] = 2; - SU2ToCGNS[16] = 16; - SU2ToCGNS[17] = 36; - SU2ToCGNS[18] = 37; - SU2ToCGNS[19] = 18; - SU2ToCGNS[20] = 49; - SU2ToCGNS[21] = 56; - SU2ToCGNS[22] = 57; - SU2ToCGNS[23] = 40; - SU2ToCGNS[24] = 48; - SU2ToCGNS[25] = 59; - SU2ToCGNS[26] = 58; - SU2ToCGNS[27] = 41; - SU2ToCGNS[28] = 22; - SU2ToCGNS[29] = 45; - SU2ToCGNS[30] = 44; - SU2ToCGNS[31] = 20; - SU2ToCGNS[32] = 17; - SU2ToCGNS[33] = 39; - SU2ToCGNS[34] = 38; - SU2ToCGNS[35] = 19; - SU2ToCGNS[36] = 50; - SU2ToCGNS[37] = 60; - SU2ToCGNS[38] = 61; - SU2ToCGNS[39] = 43; - SU2ToCGNS[40] = 51; - SU2ToCGNS[41] = 63; - SU2ToCGNS[42] = 62; - SU2ToCGNS[43] = 42; - SU2ToCGNS[44] = 23; - SU2ToCGNS[45] = 46; - SU2ToCGNS[46] = 47; - SU2ToCGNS[47] = 21; - SU2ToCGNS[48] = 4; - SU2ToCGNS[49] = 24; - SU2ToCGNS[50] = 25; - SU2ToCGNS[51] = 5; - SU2ToCGNS[52] = 31; - SU2ToCGNS[53] = 52; - SU2ToCGNS[54] = 53; - SU2ToCGNS[55] = 26; - SU2ToCGNS[56] = 30; - SU2ToCGNS[57] = 55; - SU2ToCGNS[58] = 54; - SU2ToCGNS[59] = 27; - SU2ToCGNS[60] = 7; - SU2ToCGNS[61] = 29; - SU2ToCGNS[62] = 28; - SU2ToCGNS[63] = 6; -} - -void CCGNSElementType::CreateDataHEXA_125(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, - vector& SU2ToCGNS) { - /* The HEXA_125 element is a quartic hexahedron. In CGNS the nodes are - numbered as follows: - First the vertex nodes. - - Second the edge nodes. - - Third the face nodes. - - Fourth the volume nodes. - In SU2 the node numbering takes place along increasing i-, j- and k-lines, - where the i-direction is defined from node 0 to 1 and the j-direction - from node 0 along the second edge and the k-direction from node 0 along - the third edge. */ - VTK_Type = HEXAHEDRON; - nPoly = 4; - nDOFs = 125; - - SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; - SU2ToCGNS[1] = 8; - SU2ToCGNS[2] = 9; - SU2ToCGNS[3] = 10; - SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 19; - SU2ToCGNS[6] = 44; - SU2ToCGNS[7] = 45; - SU2ToCGNS[8] = 46; - SU2ToCGNS[9] = 11; - SU2ToCGNS[10] = 18; - SU2ToCGNS[11] = 51; - SU2ToCGNS[12] = 52; - SU2ToCGNS[13] = 47; - SU2ToCGNS[14] = 12; - SU2ToCGNS[15] = 17; - SU2ToCGNS[16] = 50; - SU2ToCGNS[17] = 49; - SU2ToCGNS[18] = 48; - SU2ToCGNS[19] = 13; - SU2ToCGNS[20] = 3; - SU2ToCGNS[21] = 16; - SU2ToCGNS[22] = 15; - SU2ToCGNS[23] = 14; - SU2ToCGNS[24] = 2; - SU2ToCGNS[25] = 20; - SU2ToCGNS[26] = 53; - SU2ToCGNS[27] = 54; - SU2ToCGNS[28] = 55; - SU2ToCGNS[29] = 23; - SU2ToCGNS[30] = 82; - SU2ToCGNS[31] = 98; - SU2ToCGNS[32] = 99; - SU2ToCGNS[33] = 100; - SU2ToCGNS[34] = 62; - SU2ToCGNS[35] = 81; - SU2ToCGNS[36] = 105; - SU2ToCGNS[37] = 106; - SU2ToCGNS[38] = 101; - SU2ToCGNS[39] = 63; - SU2ToCGNS[40] = 80; - SU2ToCGNS[41] = 104; - SU2ToCGNS[42] = 103; - SU2ToCGNS[43] = 102; - SU2ToCGNS[44] = 64; - SU2ToCGNS[45] = 29; - SU2ToCGNS[46] = 73; - SU2ToCGNS[47] = 72; - SU2ToCGNS[48] = 71; - SU2ToCGNS[49] = 26; - SU2ToCGNS[50] = 21; - SU2ToCGNS[51] = 60; - SU2ToCGNS[52] = 61; - SU2ToCGNS[53] = 56; - SU2ToCGNS[54] = 24; - SU2ToCGNS[55] = 83; - SU2ToCGNS[56] = 107; - SU2ToCGNS[57] = 108; - SU2ToCGNS[58] = 109; - SU2ToCGNS[59] = 69; - SU2ToCGNS[60] = 88; - SU2ToCGNS[61] = 114; - SU2ToCGNS[62] = 115; - SU2ToCGNS[63] = 110; - SU2ToCGNS[64] = 70; - SU2ToCGNS[65] = 87; - SU2ToCGNS[66] = 113; - SU2ToCGNS[67] = 112; - SU2ToCGNS[68] = 111; - SU2ToCGNS[69] = 65; - SU2ToCGNS[70] = 30; - SU2ToCGNS[71] = 74; - SU2ToCGNS[72] = 79; - SU2ToCGNS[73] = 78; - SU2ToCGNS[74] = 27; - SU2ToCGNS[75] = 22; - SU2ToCGNS[76] = 59; - SU2ToCGNS[77] = 58; - SU2ToCGNS[78] = 57; - SU2ToCGNS[79] = 25; - SU2ToCGNS[80] = 84; - SU2ToCGNS[81] = 116; - SU2ToCGNS[82] = 117; - SU2ToCGNS[83] = 118; - SU2ToCGNS[84] = 68; - SU2ToCGNS[85] = 85; - SU2ToCGNS[86] = 123; - SU2ToCGNS[87] = 124; - SU2ToCGNS[88] = 119; - SU2ToCGNS[89] = 67; - SU2ToCGNS[90] = 86; - SU2ToCGNS[91] = 122; - SU2ToCGNS[92] = 121; - SU2ToCGNS[93] = 120; - SU2ToCGNS[94] = 66; - SU2ToCGNS[95] = 31; - SU2ToCGNS[96] = 75; - SU2ToCGNS[97] = 76; - SU2ToCGNS[98] = 77; - SU2ToCGNS[99] = 28; - SU2ToCGNS[100] = 4; - SU2ToCGNS[101] = 32; - SU2ToCGNS[102] = 33; - SU2ToCGNS[103] = 34; - SU2ToCGNS[104] = 5; - SU2ToCGNS[105] = 43; - SU2ToCGNS[106] = 89; - SU2ToCGNS[107] = 90; - SU2ToCGNS[108] = 91; - SU2ToCGNS[109] = 35; - SU2ToCGNS[110] = 42; - SU2ToCGNS[111] = 96; - SU2ToCGNS[112] = 97; - SU2ToCGNS[113] = 92; - SU2ToCGNS[114] = 36; - SU2ToCGNS[115] = 41; - SU2ToCGNS[116] = 95; - SU2ToCGNS[117] = 94; - SU2ToCGNS[118] = 93; - SU2ToCGNS[119] = 37; - SU2ToCGNS[120] = 7; - SU2ToCGNS[121] = 40; - SU2ToCGNS[122] = 39; - SU2ToCGNS[123] = 38; - SU2ToCGNS[124] = 6; -} - -#endif -#endif diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index d9536a67903..0af57647bac 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -30,9 +30,6 @@ #include "../../include/geometry/primal_grid/CPrimalGridFEM.hpp" #include "../../include/geometry/primal_grid/CPrimalGridBoundFEM.hpp" -#ifdef HAVE_CGNS -#include "../../include/fem/fem_cgns_elements.hpp" -#endif #include "../../include/adt/CADTElemClass.hpp" #include "../../include/linear_algebra/blas_structure.hpp" @@ -802,1067 +799,6 @@ void CPhysicalGeometry::Read_SU2_Format_Parallel_FEM(CConfig* config, const stri mesh_file.close(); } -void CPhysicalGeometry::Read_CGNS_Format_Parallel_FEM(CConfig* config, const string& val_mesh_filename, - unsigned short val_iZone, unsigned short val_nZone) { -#ifdef HAVE_CGNS - - /*--- For proper support of the high order elements, at least version 3.3 - of CGNS must be used. Check this. ---*/ -#if CGNS_VERSION >= 3300 - - /*--- Check whether the supplied file is truly a CGNS file. ---*/ - int file_type; - if (cg_is_cgns(val_mesh_filename.c_str(), &file_type) != CG_OK) - SU2_MPI::Error(val_mesh_filename + string(" is not a CGNS file that can be read."), CURRENT_FUNCTION); - - /*--- Initialize counters for local/global points & elements ---*/ - Global_nPoint = 0; - Global_nPointDomain = 0; - Global_nElem = 0; - nelem_edge = 0; - Global_nelem_edge = 0; - nelem_triangle = 0; - Global_nelem_triangle = 0; - nelem_quad = 0; - Global_nelem_quad = 0; - nelem_tetra = 0; - Global_nelem_tetra = 0; - nelem_hexa = 0; - Global_nelem_hexa = 0; - nelem_prism = 0; - Global_nelem_prism = 0; - nelem_pyramid = 0; - Global_nelem_pyramid = 0; - - /*--------------------------------------------------------------------------*/ - /*--- Checking of the file, determine the dimensions, etc. ---*/ - /*--------------------------------------------------------------------------*/ - - /*--- Allocate memory for the linear partition of the elements of the mesh. - These arrays are the size of the number of ranks. ---*/ - beg_node = new unsigned long[size]; - end_node = new unsigned long[size]; - nPointLinear = new unsigned long[size]; - - /* Open the CGNS file for reading and check if it went OK. */ - int fn; - if (cg_open(val_mesh_filename.c_str(), CG_MODE_READ, &fn) != CG_OK) cg_error_exit(); - if (rank == MASTER_NODE) { - cout << "Reading the CGNS file: " << val_mesh_filename << "." << endl; - } - - /* Get the number of databases. This is the highest node in the CGNS heirarchy. - The current implementation assumes that there is only one database. */ - int nbases; - if (cg_nbases(fn, &nbases) != CG_OK) cg_error_exit(); - if (nbases > 1) { - ostringstream message; - message << "CGNS file contains " << nbases << " databases." << endl; - message << "CGNS reader can handle only 1 at the moment." << endl; - - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - /* Read the information of the base, especially the number of dimensions. */ - char cgnsname[CGNS_STRING_SIZE]; - int cellDim, physDim; - const int iBase = 1; - if (cg_base_read(fn, iBase, cgnsname, &cellDim, &physDim)) cg_error_exit(); - nDim = physDim; - - if (cellDim != physDim) { - ostringstream message; - message << "The element dimension, " << cellDim << ", differs from the physical dimension, " << physDim << "." - << endl; - message << "These should be the same for the DG-FEM solver." << endl; - - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - /* Write the info about the number of dimensions. */ - if (rank == MASTER_NODE) { - if (nDim == 2) cout << "Two dimensional problem." << endl; - if (nDim == 3) cout << "Three dimensional problem." << endl; - } - - /* Set the zone ID for CGNS, CGNS indices starts at 1, and check - if the requested zone ID is a valid one. */ - const int iZone = val_iZone + 1; - - int nzones; - if (cg_nzones(fn, iBase, &nzones) != CG_OK) cg_error_exit(); - if (iZone < 1 || iZone > nzones) { - ostringstream message; - message << "Zone " << iZone << " requested for reading, but there are only " << nzones - << " zones present in the CGNS file." << endl; - - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - /* Determine the zone type for the requested zone and check if it is - unstructured. */ - ZoneType_t zoneType; - if (cg_zone_type(fn, iBase, iZone, &zoneType) != CG_OK) cg_error_exit(); - if (zoneType != Unstructured) - SU2_MPI::Error("Structured CGNS zone found while unstructured expected.", CURRENT_FUNCTION); - - /* Determine the number of sections for the connectivities in this zone. */ - int nsections; - if (cg_nsections(fn, iBase, iZone, &nsections) != CG_OK) cg_error_exit(); - - /*--------------------------------------------------------------------------*/ - /*--- Reading and distributing the volume elements. ---*/ - /*--------------------------------------------------------------------------*/ - - /* Loop over the sections to store the meta data in CGNSElemTypes - and to determine the number of volume elements. - Note that the indices start at 1 in CGNS. */ - vector CGNSElemTypes(nsections); - - for (int iConn = 1; iConn <= nsections; ++iConn) { - CGNSElemTypes[iConn - 1].DetermineMetaData(nDim, fn, iBase, iZone, iConn); - if (CGNSElemTypes[iConn - 1].volumeConn) Global_nElem += CGNSElemTypes[iConn - 1].nElem; - } - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << Global_nElem << " interior elements before parallel partitioning." << endl; - - /*--- Check if the number of cores used is larger than the number of - elements. Terminate if this is the case, because it does not make - sense to do this. ---*/ - unsigned long nCores = size; // Correct for the number of cores per rank. - if (nCores > Global_nElem) { - ostringstream message; - message << "The number of cores, " << nCores; - message << ", is larger than the number of elements, " << Global_nElem << "." << endl; - message << "This is not an efficient use of the resources and therefore " - << "SU2 will terminate."; - - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - /*--- Compute the number of elements that will be stored on each rank. - This is a linear partitioning with the addition of a simple load - balancing for any remainder elements. ---*/ - unsigned long total_elem_accounted = 0; - for (unsigned long i = 0; i < (unsigned long)size; i++) { - nPointLinear[i] = Global_nElem / size; - total_elem_accounted = total_elem_accounted + nPointLinear[i]; - } - - /*--- Get the number of remainder elements after the even division ---*/ - const unsigned long rem_elem = Global_nElem - total_elem_accounted; - for (unsigned long i = 0; i < rem_elem; i++) { - ++nPointLinear[i]; - } - - /*--- Store the local number of elements and the beginning/end index ---*/ - nElem = nPointLinear[rank]; - beg_node[0] = 0; - end_node[0] = beg_node[0] + nPointLinear[0]; - for (int i = 1; i < size; i++) { - beg_node[i] = end_node[i - 1]; - end_node[i] = beg_node[i] + nPointLinear[i]; - } - - /*--- Allocate space for elements ---*/ - elem = new CPrimalGrid*[nElem](); - - /*--- Loop over over the connectivities and read the elements to be stored on - this rank. Furthermore, determine the local amount of DOFs for the - solution (which may differ from the number of DOFS for the grid). ---*/ - unsigned long nDOFsLoc = 0, elemCount = 0, locElemCount = 0; - - for (int iConn = 0; iConn < nsections; ++iConn) { - if (CGNSElemTypes[iConn].volumeConn) { - /* Determine the global volume element range for this connectivity. */ - const unsigned long elemCountOld = elemCount; - elemCount += CGNSElemTypes[iConn].nElem; - - /* Check for overlap with the element range this rank is responsible for. */ - const unsigned long indBegOverlap = max(elemCountOld, beg_node[rank]); - const unsigned long indEndOverlap = min(elemCount, end_node[rank]); - - if (indEndOverlap > indBegOverlap) { - /* This rank must read element data from this connectivity section. - Determine the offset relative to the start of this section and the - number of elements to be read by this rank. */ - const unsigned long offsetRank = indBegOverlap - elemCountOld; - const unsigned long nElemRank = indEndOverlap - indBegOverlap; - - /* Read the connectivity range determined above. */ - CGNSElemTypes[iConn].ReadConnectivityRange(fn, iBase, iZone, offsetRank, nElemRank, beg_node[rank], elem, - locElemCount, nDOFsLoc); - } - } - } - -#ifdef HAVE_MPI - /* The global offset of the DOFs must be corrected when running in - parallel. Therefore gather the number of DOFs of all the ranks. */ - vector nDOFsPerRank(size); - SU2_MPI::Allgather(&nDOFsLoc, 1, MPI_UNSIGNED_LONG, nDOFsPerRank.data(), 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); - - /* Determine the offset for the DOFs on this rank. */ - unsigned long offsetRank = 0; - for (int i = 0; i < rank; ++i) offsetRank += nDOFsPerRank[i]; - - /* Loop over the local elements to correct the global offset of the DOFs. */ - for (unsigned long i = 0; i < nElem; ++i) elem[i]->AddOffsetGlobalDOFs(offsetRank); -#endif - - /*--------------------------------------------------------------------------*/ - /*--- Reading and distributing the coordinates. ---*/ - /*--------------------------------------------------------------------------*/ - - /* Determine the global number of vertices in the requested zone. - The other size information is not used. */ - cgsize_t sizes[3]; - if (cg_zone_read(fn, iBase, iZone, cgnsname, sizes) != CG_OK) cg_error_exit(); - Global_nPoint = sizes[0]; - - /*--- Determine the number of points per rank in cumulative storage format. - This is done to avoid that every rank reads all the coordinates. - The required coordinates for each rank are later obtained via - communication. ---*/ - unsigned long totalPointsAccounted = 0; - vector nPointsPerRank(size + 1); - for (int i = 1; i <= size; ++i) { - nPointsPerRank[i] = Global_nPoint / size; - totalPointsAccounted += nPointsPerRank[i]; - } - - const unsigned long nPointsRem = Global_nPoint - totalPointsAccounted; - for (unsigned long i = 1; i <= nPointsRem; ++i) ++nPointsPerRank[i]; - - nPointsPerRank[0] = 0; - for (int i = 0; i < size; ++i) nPointsPerRank[i + 1] += nPointsPerRank[i]; - - /* Determine the number of points that must be read by this rank and - allocate the memory for the coordinate buffers. */ - const cgsize_t nPointsRead = nPointsPerRank[rank + 1] - nPointsPerRank[rank]; - vector > coorBuf(nDim, vector(nPointsRead)); - - /* Loop over the number of dimensions to read the coordinates. Note that - the loop starts at 1 and ends at nDim because CGNS requires this. */ - for (unsigned short iDim = 1; iDim <= nDim; ++iDim) { - /* Determine the data type and name of the coordinate. Copy the name - of the coordinate in a string for easier comparison. */ - DataType_t datatype; - if (cg_coord_info(fn, iBase, iZone, iDim, &datatype, cgnsname) != CG_OK) cg_error_exit(); - string coorname = cgnsname; - - /* Check the name of the coordinate and determine the index in coorBuf - where to store this coordinate. Normally this should be iDim-1. */ - unsigned short indC = 0; - if (coorname == "CoordinateX") - indC = 0; - else if (coorname == "CoordinateY") - indC = 1; - else if (coorname == "CoordinateZ") - indC = 2; - else - SU2_MPI::Error(string("Unknown coordinate name, ") + coorname + string(", encountered in the CGNS file."), - CURRENT_FUNCTION); - - /* Easier storage of the range in the CGNS file. */ - cgsize_t range_min = nPointsPerRank[rank] + 1; - cgsize_t range_max = nPointsPerRank[rank + 1]; - - /*--- Read the coordinate with the required precision and copy - this data to the correct index in coorBuf. ---*/ - switch (datatype) { - case RealSingle: { - /* Single precision used. */ - vector buf(nPointsRead); - if (cg_coord_read(fn, iBase, iZone, cgnsname, datatype, &range_min, &range_max, buf.data()) != CG_OK) - cg_error_exit(); - - for (cgsize_t i = 0; i < nPointsRead; ++i) coorBuf[indC][i] = buf[i]; - break; - } - - case RealDouble: { - /* Double precision used. */ - vector buf(nPointsRead); - if (cg_coord_read(fn, iBase, iZone, cgnsname, datatype, &range_min, &range_max, buf.data()) != CG_OK) - cg_error_exit(); - - for (cgsize_t i = 0; i < nPointsRead; ++i) coorBuf[indC][i] = buf[i]; - break; - } - - default: { - ostringstream message; - message << "Datatype for coordinates must be RealSingle or RealDouble, " - << "not " << datatype << endl; - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - } - } - - /* Make a distinction between sequential and parallel mode. */ -#ifdef HAVE_MPI - /*--- Parallel mode. Create a vector, which contains the global - node IDs of the local elements. ---*/ - vector nodeIDsElemLoc; - nodeIDsElemLoc.reserve(nDOFsLoc); - for (unsigned long i = 0; i < locElemCount; ++i) { - unsigned short nDOFsElem = elem[i]->GetnNodes(); - for (unsigned short j = 0; j < nDOFsElem; ++j) nodeIDsElemLoc.push_back(elem[i]->GetNode(j)); - } - - sort(nodeIDsElemLoc.begin(), nodeIDsElemLoc.end()); - vector::iterator lastNode; - lastNode = unique(nodeIDsElemLoc.begin(), nodeIDsElemLoc.end()); - nodeIDsElemLoc.erase(lastNode, nodeIDsElemLoc.end()); - - /*--- Allocate the memory for the coordinates to be stored on this rank. ---*/ - nPoint = nodeIDsElemLoc.size(); - nodes = new CPoint(nPoint, nDim); - - /*--- Store the global ID's of the nodes in such a way that they can - be sent to the rank that actually stores the coordinates.. ---*/ - vector > nodeBuf(size, vector(0)); - for (unsigned long i = 0; i < nodeIDsElemLoc.size(); ++i) { - const cgsize_t nodeID = nodeIDsElemLoc[i]; - vector::iterator low; - low = lower_bound(nPointsPerRank.begin(), nPointsPerRank.end(), nodeID); - cgsize_t rankNode = low - nPointsPerRank.begin(); - if (*low > nodeID) --rankNode; - - nodeBuf[rankNode].push_back(nodeIDsElemLoc[i]); - } - - /*--- Determine the total number of ranks to which this rank will send - a message and also determine the number of ranks from which this - rank will receive a message. Furthermore, determine the starting - indices where data from the different ranks should be stored in - node. ---*/ - int nRankSend = 0; - vector sendToRank(size, 0); - vector startingIndRanksInNode(size + 1); - startingIndRanksInNode[0] = 0; - - for (int i = 0; i < size; ++i) { - startingIndRanksInNode[i + 1] = startingIndRanksInNode[i] + nodeBuf[i].size(); - - if (!nodeBuf[i].empty()) { - ++nRankSend; - sendToRank[i] = 1; - } - } - - int nRankRecv; - vector sizeRecv(size, 1); - SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), MPI_INT, MPI_SUM, SU2_MPI::GetComm()); - - /*--- Send out the messages with the global node numbers. Use nonblocking - sends to avoid deadlock. ---*/ - vector sendReqs(nRankSend); - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!nodeBuf[i].empty()) { - SU2_MPI::Isend(nodeBuf[i].data(), nodeBuf[i].size(), MPI_UNSIGNED_LONG, i, i, SU2_MPI::GetComm(), - &sendReqs[nRankSend]); - ++nRankSend; - } - } - - /* Define the communication buffer for the coordinates and the vector - for the return communication requests. */ - vector returnReqs(nRankRecv); - vector > coorReturnBuf(nRankRecv, vector(0)); - - /*--- Loop over the number of ranks from which this rank receives global - point numbers that should be stored on this rank. ---*/ - for (int i = 0; i < nRankRecv; ++i) { - /* Block until a message arrives. Determine the source and size - of the message. */ - SU2_MPI::Status status; - SU2_MPI::Probe(MPI_ANY_SOURCE, rank, SU2_MPI::GetComm(), &status); - int source = status.MPI_SOURCE; - - int sizeMess; - SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &sizeMess); - - /* Allocate the memory for a buffer to receive this message and also - for the buffer to return to coordinates. */ - vector nodeRecvBuf(sizeMess); - coorReturnBuf[i].resize(nDim * sizeMess); - - /* Receive the message using a blocking receive. */ - SU2_MPI::Recv(nodeRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, source, rank, SU2_MPI::GetComm(), &status); - - /*--- Loop over the nodes just received and fill the return communication - buffer with the coordinates of the requested nodes. ---*/ - for (int j = 0; j < sizeMess; ++j) { - const int jj = nDim * j; - const long kk = nodeRecvBuf[j] - nPointsPerRank[rank]; - if (kk < 0 || kk >= nPointsRead) - SU2_MPI::Error("Invalid point requested. This should not happen.", CURRENT_FUNCTION); - - for (unsigned short k = 0; k < nDim; ++k) coorReturnBuf[i][jj + k] = coorBuf[k][kk]; - } - - /* Send the buffer just filled back to the requesting rank. - Use a non-blocking send to avoid deadlock. */ - SU2_MPI::Isend(coorReturnBuf[i].data(), coorReturnBuf[i].size(), MPI_DOUBLE, source, source + 1, SU2_MPI::GetComm(), - &returnReqs[i]); - } - - /* Loop over the ranks from which this rank has requested coordinates. */ - for (int i = 0; i < nRankSend; ++i) { - /* Block until a message arrives. Determine the source of the message. */ - SU2_MPI::Status status; - SU2_MPI::Probe(MPI_ANY_SOURCE, rank + 1, SU2_MPI::GetComm(), &status); - int source = status.MPI_SOURCE; - - /* Allocate the memory for the coordinate receive buffer. */ - vector coorRecvBuf(nDim * nodeBuf[source].size()); - - /* Receive the message using a blocking receive. */ - SU2_MPI::Recv(coorRecvBuf.data(), coorRecvBuf.size(), MPI_DOUBLE, source, rank + 1, SU2_MPI::GetComm(), &status); - - /*--- Make a distinction between 2D and 3D to store the data of the nodes. - This data is created by taking the offset of the source rank into - account. In this way the nodes are numbered with increading - global node ID. ---*/ - for (unsigned long j = 0; j < nodeBuf[source].size(); ++j) { - const unsigned long jj = nDim * j; - const unsigned long kk = startingIndRanksInNode[source] + j; - - nodes->SetCoord(kk, &coorRecvBuf[jj]); - nodes->SetGlobalIndex(kk, nodeBuf[source][j]); - } - } - - /* Complete the non-blocking sends of both rounds. */ - SU2_MPI::Waitall(sendReqs.size(), sendReqs.data(), MPI_STATUSES_IGNORE); - SU2_MPI::Waitall(returnReqs.size(), returnReqs.data(), MPI_STATUSES_IGNORE); - - /* Wild cards have been used in the communication, - so synchronize the ranks to avoid problems. */ - SU2_MPI::Barrier(SU2_MPI::GetComm()); - -#else - /*--- Sequential mode. Create the data for the points. The global - number of points equals the local number of points. ---*/ - nPoint = Global_nPoint; - nodes = new CPoint(nPoint, nDim); - - for (unsigned long i = 0; i < nPoint; ++i) { - for (unsigned short iDim = 0; iDim < nDim; ++iDim) nodes->SetCoord(i, iDim, coorBuf[iDim][i]); - nodes->SetGlobalIndex(i, i); - } - -#endif - - /*--------------------------------------------------------------------------*/ - /*--- Determine and distribute the single faces of the elements. These ---*/ - /*--- faces are distributed over the ranks such that later the boundary ---*/ - /*--- can retrieve the info on which rank they must be stored without ---*/ - /*--- each rank having to read the entire connectivity data. ---*/ - /*--------------------------------------------------------------------------*/ - - /*--- Determine the faces of the local elements. --- */ - vector localFaces; - for (unsigned long k = 0; k < nElem; ++k) { - /*--- Get the global IDs of the corner points of all the faces of this elements. ---*/ - unsigned short nFaces; - unsigned short nPointsPerFace[6]; - unsigned long faceConn[6][4]; - - elem[k]->GetCornerPointsAllFaces(nFaces, nPointsPerFace, faceConn); - - /*--- Loop over the faces and add them to localFaces. For consistency - between sequential and parallel mode the rank is stored at the - position for the second element ID. ---*/ - for (unsigned short i = 0; i < nFaces; ++i) { - CFaceOfElement thisFace; - thisFace.nCornerPoints = nPointsPerFace[i]; - for (unsigned short j = 0; j < nPointsPerFace[i]; ++j) thisFace.cornerPoints[j] = faceConn[i][j]; - thisFace.elemID0 = k + beg_node[rank]; - thisFace.elemID1 = rank; - - thisFace.CreateUniqueNumbering(); - localFaces.push_back(thisFace); - } - } - - /*--- Sort localFaces in increasing order and remove the double entities, - such that unnecessary data is not communicated later on. ---*/ - sort(localFaces.begin(), localFaces.end()); - vector::iterator lastFace; - lastFace = unique(localFaces.begin(), localFaces.end()); - localFaces.erase(lastFace, localFaces.end()); - -#ifdef HAVE_MPI - - /*--- In parallel mode these faces must be distributed over the ranks. - A face is stored on the rank where its first node ID is located - based on nPointsPerRank. Define the communication buffers and - determine their contents. ---*/ - vector > faceBuf(size, vector(0)); - for (unsigned long i = 0; i < localFaces.size(); ++i) { - const cgsize_t nodeID = localFaces[i].cornerPoints[0]; - vector::iterator low; - low = lower_bound(nPointsPerRank.begin(), nPointsPerRank.end(), nodeID); - cgsize_t rankNode = low - nPointsPerRank.begin(); - if (*low > nodeID) --rankNode; - - faceBuf[rankNode].push_back(localFaces[i].nCornerPoints); - for (unsigned short j = 0; j < localFaces[i].nCornerPoints; ++j) - faceBuf[rankNode].push_back(localFaces[i].cornerPoints[j]); - faceBuf[rankNode].push_back(localFaces[i].elemID0); - } - - /* Delete the memory of localFaces again, because its contents will be - build from the messages that this rank will receive. */ - localFaces.clear(); - - /*--- Determine the number of messages this rank will send and receive. ---*/ - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!faceBuf[i].empty()) { - ++nRankSend; - sendToRank[i] = 1; - } else { - sendToRank[i] = 0; - } - } - - SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), MPI_INT, MPI_SUM, SU2_MPI::GetComm()); - - /*--- Send the messages using non-blocking sends to avoid deadlock. ---*/ - sendReqs.resize(nRankSend); - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!faceBuf[i].empty()) { - SU2_MPI::Isend(faceBuf[i].data(), faceBuf[i].size(), MPI_UNSIGNED_LONG, i, i + 4, SU2_MPI::GetComm(), - &sendReqs[nRankSend]); - ++nRankSend; - } - } - - /* Loop over the number of ranks from which this rank will receive data. */ - for (int i = 0; i < nRankRecv; ++i) { - /* Block until a message arrives and determine the source and size - of the message. */ - SU2_MPI::Status status; - SU2_MPI::Probe(MPI_ANY_SOURCE, rank + 4, SU2_MPI::GetComm(), &status); - int source = status.MPI_SOURCE; - - int sizeMess; - SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &sizeMess); - - /* Allocate the memory for the receive buffer and receive the - message using a non-blocking receive. */ - vector faceRecvBuf(sizeMess); - SU2_MPI::Recv(faceRecvBuf.data(), faceRecvBuf.size(), MPI_UNSIGNED_LONG, source, rank + 4, SU2_MPI::GetComm(), - &status); - - /* Loop to extract the data from the receive buffer. */ - int ii = 0; - while (ii < sizeMess) { - /* Store the data for this face in localFaces. The rank where the - corresponding element is physically present is stored in the - second element ID. Note that it is not necessary to create a unique - numbering anymore, because this has already been done before the - communication buffer was created. */ - CFaceOfElement thisFace; - thisFace.nCornerPoints = (unsigned short)faceRecvBuf[ii++]; - for (unsigned short j = 0; j < thisFace.nCornerPoints; ++j, ++ii) thisFace.cornerPoints[j] = faceRecvBuf[ii]; - thisFace.elemID0 = faceRecvBuf[ii++]; - - thisFace.elemID1 = source; - localFaces.push_back(thisFace); - } - } - - /*--- Sort localFaces in increasing order and remove the double entities, - such that searching is a bit more efficient later on. ---*/ - sort(localFaces.begin(), localFaces.end()); - lastFace = unique(localFaces.begin(), localFaces.end()); - localFaces.erase(lastFace, localFaces.end()); - - /* Complete the non-blocking sends. Afterwards, synchronize the ranks, - because wild cards have been used. */ - SU2_MPI::Waitall(sendReqs.size(), sendReqs.data(), MPI_STATUSES_IGNORE); - SU2_MPI::Barrier(SU2_MPI::GetComm()); - -#endif - - /*--------------------------------------------------------------------------*/ - /*--- Reading and distributing the surface elements. ---*/ - /*--------------------------------------------------------------------------*/ - - /* Determine the number of families in this base and read their names. - Note that when multiple zones are present, this step is repeated for - every zone. */ - int nFamilies; - if (cg_nfamilies(fn, iBase, &nFamilies) != CG_OK) cg_error_exit(); - - vector familyNames(nFamilies); - for (int i = 1; i <= nFamilies; ++i) { - int nFamBC, nGeo; - if (cg_family_read(fn, iBase, i, cgnsname, &nFamBC, &nGeo) != CG_OK) cg_error_exit(); - familyNames[i - 1] = cgnsname; - } - - /* Determine the number of boundary conditions for this zone. */ - int nBCs; - if (cg_nbocos(fn, iBase, iZone, &nBCs) != CG_OK) cg_error_exit(); - - /* Read the names of the boundary conditions and determine their family names. - If not family name is specified for a boundary condition, the family name - is set to the name of the boundary condition. */ - vector BCNames(nBCs), BCFamilyNames(nBCs); - for (int i = 1; i <= nBCs; ++i) { - /* Read the info for this boundary condition. */ - BCType_t BCType; - PointSetType_t ptsetType; - cgsize_t npnts, NormalListSize; - int NormalIndex, nDataSet; - DataType_t NormalDataType; - if (cg_boco_info(fn, iBase, iZone, i, cgnsname, &BCType, &ptsetType, &npnts, &NormalIndex, &NormalListSize, - &NormalDataType, &nDataSet) != CG_OK) - cg_error_exit(); - BCNames[i - 1] = cgnsname; - - /* Read the possibly family name and set it. If not present, it is - equal to BCName. */ - if (cg_goto(fn, iBase, "Zone_t", iZone, "ZoneBC_t", 1, "BC_t", i, "end") != CG_OK) cg_error_exit(); - - int ierr = cg_famname_read(cgnsname); - if (ierr == CG_ERROR) - cg_error_exit(); - else if (ierr == CG_OK) - BCFamilyNames[i - 1] = cgnsname; - else - BCFamilyNames[i - 1] = BCNames[i - 1]; - } - - /*--- Determine the number of different surface connectivities. It is - possible to specify a family name for a surface connectivity. If that - family name is the same for multiple surface connectivities, these - connectivities are merged together for the boundary condition - treatment in the DG-FEM solver. ---*/ - vector surfaceNames; - vector > surfaceConnIDs; - - for (int i = 0; i < nsections; ++i) { - if (CGNSElemTypes[i].surfaceConn) { - /*--- Determine the surface name to use for this connectivity. - This name is determined as follows (in terms of importance). - 1) Family name specified for this connectivity. - 2) Family name of the corresponding boundary condition, - if present. - 3) Name of the connectivity. ---*/ - string thisSurfaceName; - const int connID = CGNSElemTypes[i].connID; - - /* First try to read the family name for the connectivity. */ - if (cg_goto(fn, iBase, "Zone_t", iZone, "Elements_t", connID, "end") != CG_OK) cg_error_exit(); - int ierr = cg_famname_read(cgnsname); - if (ierr == CG_ERROR) - cg_error_exit(); - else if (ierr == CG_OK) - thisSurfaceName = cgnsname; - else { - /* No family name. Check the boundary conditions. It is assumed that - the boundary conditions have the same name as the connectivities. */ - int j; - for (j = 0; j < nBCs; ++j) { - if (BCNames[j] == CGNSElemTypes[i].connName) { - thisSurfaceName = BCFamilyNames[j]; - break; - } - } - - /* If the name is not found in the boundary conditions, set the name - of this surface connectivity to the name of this connectivity. */ - if (j == nBCs) thisSurfaceName = CGNSElemTypes[i].connName; - } - - /* Loop over the previously stored surface names and check if this - surface name is already present. */ - unsigned long j; - for (j = 0; j < surfaceNames.size(); ++j) { - if (thisSurfaceName == surfaceNames[j]) { - surfaceConnIDs[j].push_back(i); - } - } - - /* If the surface name is not stored yet, create new entries in - surfaceNames and surfaceConnIDs. */ - if (j == surfaceNames.size()) { - surfaceNames.push_back(thisSurfaceName); - vector thisSurfaceConn(1, i); - surfaceConnIDs.push_back(thisSurfaceConn); - } - } - } - - /* Write a message about the number of surface markers and allocate the - memory for the data structures to store the required information. */ - nMarker = surfaceNames.size(); - if (rank == MASTER_NODE) cout << nMarker << " surface markers." << endl; - config->SetnMarker_All(nMarker); - - unsigned short nMarker_Max = config->GetnMarker_Max(); - - bound = new CPrimalGrid**[nMarker]; - nElem_Bound = new unsigned long[nMarker]; - Tag_to_Marker = new string[nMarker_Max]; - - /* Loop over the number of markers to read and distribute the connectivities. */ - for (unsigned short iMarker = 0; iMarker < nMarker; ++iMarker) { - /* Easier storage of the entries in CGNSElemTypes that contribute - to this boundary marker. */ - const int nEntries = surfaceConnIDs[iMarker].size(); - const int* entries = surfaceConnIDs[iMarker].data(); - - /* Determine the global number of elements for this boundary marker. */ - cgsize_t nElem_Bound_Global = 0; - for (int iConn = 0; iConn < nEntries; ++iConn) nElem_Bound_Global += CGNSElemTypes[entries[iConn]].nElem; - - /* Write a message about the global number of surface elements - present in this marker. */ - string Marker_Tag = surfaceNames[iMarker]; - if (rank == MASTER_NODE) - cout << nElem_Bound_Global << " boundary elements in index " << iMarker << " (Marker = " << Marker_Tag << ")." - << endl; - - /* Determine the number of surface elements per rank in cumulative storage - format. This is done to avoid that every rank reads all the elements. - This is to avoid that every rank reads all the elements. The correct - rank for storage is determined later via communication. */ - unsigned long totalBoundElemAccounted = 0; - vector nBoundElemPerRank(size + 1); - for (int i = 1; i <= size; ++i) { - nBoundElemPerRank[i] = nElem_Bound_Global / size; - totalBoundElemAccounted += nBoundElemPerRank[i]; - } - - const unsigned long nBoundElemRem = nElem_Bound_Global - totalBoundElemAccounted; - for (unsigned long i = 1; i <= nBoundElemRem; ++i) ++nBoundElemPerRank[i]; - - nBoundElemPerRank[0] = 0; - for (int i = 0; i < size; ++i) nBoundElemPerRank[i + 1] += nBoundElemPerRank[i]; - - /* Define a vector of FEM boundary elements to store the local - boundary faces to be read. */ - vector boundElems; - - /* Loop over the connectivity sections that contribute. */ - elemCount = locElemCount = 0; - for (int iConn = 0; iConn < nEntries; ++iConn) { - /* Determine the global range for this connectivity. */ - const unsigned long elemCountOld = elemCount; - elemCount += CGNSElemTypes[entries[iConn]].nElem; - - /* Check for overlap with the element range this rank is responsible for. */ - const unsigned long indBegOverlap = max(elemCountOld, nBoundElemPerRank[rank]); - const unsigned long indEndOverlap = min(elemCount, nBoundElemPerRank[rank + 1]); - - if (indEndOverlap > indBegOverlap) { - /* This rank must read boundary element data from this connectivity - section. Determine the offset relative to the start of this section - and the number of elements to be read by this rank. */ - const unsigned long offsetRank = indBegOverlap - elemCountOld; - const unsigned long nElemRank = indEndOverlap - indBegOverlap; - - /* Read the connectivity range determined above. */ - CGNSElemTypes[entries[iConn]].ReadBoundaryConnectivityRange(fn, iBase, iZone, offsetRank, nElemRank, - nBoundElemPerRank[rank], locElemCount, boundElems); - } - } - - /* Make a distinction between sequential and parallel mode. */ -#ifdef HAVE_MPI - /*--- Parallel mode. The information stored in boundElems must be - communicated to find out where it must be stored. First clear the - contents of the faceBuf, such that it can be used again to send - data to the appropiate rank. ---*/ - for (int i = 0; i < size; ++i) faceBuf[i].clear(); - - /*-- Loop over the locally read boundary elements and store its contents - in the appropiate location in faceBuf. ---*/ - for (unsigned long i = 0; i < boundElems.size(); ++i) { - /* Create an object of the class CFaceOfElement to determine the - node number that determines on which rank the corresponding face - in localFaces is stored. */ - CFaceOfElement thisFace(boundElems[i].VTK_Type, boundElems[i].nPolyGrid, boundElems[i].Nodes.data()); - thisFace.CreateUniqueNumbering(); - - /* Determine the rank to which this face must be sent to. */ - const cgsize_t nodeID = thisFace.cornerPoints[0]; - vector::iterator low; - low = lower_bound(nPointsPerRank.begin(), nPointsPerRank.end(), nodeID); - cgsize_t rankNode = low - nPointsPerRank.begin(); - if (*low > nodeID) --rankNode; - - /*--- Copy the relevant data of this boundary element into faceBuf. ---*/ - faceBuf[rankNode].push_back(boundElems[i].VTK_Type); - faceBuf[rankNode].push_back(boundElems[i].nPolyGrid); - faceBuf[rankNode].push_back(boundElems[i].nDOFsGrid); - faceBuf[rankNode].push_back(boundElems[i].globalBoundElemID); - faceBuf[rankNode].insert(faceBuf[rankNode].end(), boundElems[i].Nodes.begin(), boundElems[i].Nodes.end()); - } - - /* The contents of boundElems is copied into faceBuf, so it can - be released. */ - boundElems.clear(); - - /*--- Determine the number of messages this rank will send and receive. ---*/ - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!faceBuf[i].empty()) { - ++nRankSend; - sendToRank[i] = 1; - } else { - sendToRank[i] = 0; - } - } - - SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), MPI_INT, MPI_SUM, SU2_MPI::GetComm()); - - /*--- Send the messages using non-blocking sends to avoid deadlock. ---*/ - sendReqs.resize(nRankSend); - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!faceBuf[i].empty()) { - SU2_MPI::Isend(faceBuf[i].data(), faceBuf[i].size(), MPI_UNSIGNED_LONG, i, i + 5, SU2_MPI::GetComm(), - &sendReqs[nRankSend]); - ++nRankSend; - } - } - - /* Use nodeBuf as storage for the sending of the surface element data - to the correct rank. First clear its contents. */ - for (int i = 0; i < size; ++i) nodeBuf[i].clear(); - - /*--- Loop over the number of ranks from which this rank receives - surface elements to be processed. ---*/ - for (int i = 0; i < nRankRecv; ++i) { - /* Block until a message arrives. Determine the source and size - of the message. */ - SU2_MPI::Status status; - SU2_MPI::Probe(MPI_ANY_SOURCE, rank + 5, SU2_MPI::GetComm(), &status); - int source = status.MPI_SOURCE; - - int sizeMess; - SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &sizeMess); - - /* Allocate the memory for the receive buffer and receive the message - using a blocking send. */ - vector boundElemRecvBuf(sizeMess); - SU2_MPI::Recv(boundElemRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, source, rank + 5, SU2_MPI::GetComm(), - &status); - - /* Loop to extract the data from the receive buffer. */ - int ii = 0; - while (ii < sizeMess) { - /* Store the data for this boundary element. */ - const auto VTK_Type = (unsigned short)boundElemRecvBuf[ii++]; - const auto nPolyGrid = (unsigned short)boundElemRecvBuf[ii++]; - const auto nDOFsGrid = (unsigned short)boundElemRecvBuf[ii++]; - - const unsigned long globalBoundElemID = boundElemRecvBuf[ii++]; - const unsigned long* Nodes = boundElemRecvBuf.data() + ii; - ii += nDOFsGrid; - - /* Determine the corner nodes and store them in an object of - the class CFaceOfElement to carry out the search in localFaces. */ - CFaceOfElement thisFace(VTK_Type, nPolyGrid, Nodes); - - /* Check if the face is actually present. If not, print an error message - and exit. */ - thisFace.CreateUniqueNumbering(); - vector::iterator low; - low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); - - bool thisFaceFound = false; - if (low != localFaces.end()) { - if (!(thisFace < *low)) thisFaceFound = true; - } - - if (!thisFaceFound) - SU2_MPI::Error("Boundary element not found in list of faces. This is a bug.", CURRENT_FUNCTION); - - /* Determine the domain element and the rank where - this boundary element should be sent to.. */ - const unsigned long domainElementID = low->elemID0; - const int rankBoundElem = (int)low->elemID1; - - /*--- Store the data for this element in the communication buffer - for rankBoundElem. ---*/ - nodeBuf[rankBoundElem].push_back(VTK_Type); - nodeBuf[rankBoundElem].push_back(nPolyGrid); - nodeBuf[rankBoundElem].push_back(nDOFsGrid); - nodeBuf[rankBoundElem].push_back(globalBoundElemID); - nodeBuf[rankBoundElem].push_back(domainElementID); - - for (unsigned short j = 0; j < nDOFsGrid; ++j) nodeBuf[rankBoundElem].push_back(Nodes[j]); - } - } - - /* Complete the non-blocking sends. */ - SU2_MPI::Waitall(sendReqs.size(), sendReqs.data(), MPI_STATUSES_IGNORE); - - /*--- Determine the number of messages this rank will send and receive. ---*/ - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!nodeBuf[i].empty()) { - ++nRankSend; - sendToRank[i] = 1; - } else { - sendToRank[i] = 0; - } - } - - SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), MPI_INT, MPI_SUM, SU2_MPI::GetComm()); - - /*--- Send the messages using non-blocking sends to avoid deadlock. ---*/ - sendReqs.resize(nRankSend); - nRankSend = 0; - for (int i = 0; i < size; ++i) { - if (!nodeBuf[i].empty()) { - SU2_MPI::Isend(nodeBuf[i].data(), nodeBuf[i].size(), MPI_UNSIGNED_LONG, i, i + 6, SU2_MPI::GetComm(), - &sendReqs[nRankSend]); - ++nRankSend; - } - } - - /*--- Loop over the number of ranks from which this rank receives - surface elements to be stored on this rank. ---*/ - for (int i = 0; i < nRankRecv; ++i) { - /* Block until a message arrives. Determine the source and size - of the message. */ - SU2_MPI::Status status; - SU2_MPI::Probe(MPI_ANY_SOURCE, rank + 6, SU2_MPI::GetComm(), &status); - int source = status.MPI_SOURCE; - - int sizeMess; - SU2_MPI::Get_count(&status, MPI_UNSIGNED_LONG, &sizeMess); - - /* Allocate the memory for the receive buffer and receive the message - using a blocking send. */ - vector boundElemRecvBuf(sizeMess); - SU2_MPI::Recv(boundElemRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, source, rank + 6, SU2_MPI::GetComm(), - &status); - - /* Loop to extract the data from the receive buffer. */ - int ii = 0; - while (ii < sizeMess) { - /* Store the data for this boundary element. */ - const auto VTK_Type = (unsigned short)boundElemRecvBuf[ii++]; - const auto nPolyGrid = (unsigned short)boundElemRecvBuf[ii++]; - const auto nDOFsGrid = (unsigned short)boundElemRecvBuf[ii++]; - - const unsigned long globalBoundElemID = boundElemRecvBuf[ii++]; - const unsigned long domainElementID = boundElemRecvBuf[ii++]; - const unsigned long* Nodes = boundElemRecvBuf.data() + ii; - ii += nDOFsGrid; - - /* Create an object of CBoundaryFace and store it in boundElems. */ - CBoundaryFace thisBoundFace; - thisBoundFace.VTK_Type = VTK_Type; - thisBoundFace.nPolyGrid = nPolyGrid; - thisBoundFace.nDOFsGrid = nDOFsGrid; - thisBoundFace.globalBoundElemID = globalBoundElemID; - thisBoundFace.domainElementID = domainElementID; - - thisBoundFace.Nodes.resize(nDOFsGrid); - for (unsigned short j = 0; j < nDOFsGrid; ++j) thisBoundFace.Nodes[j] = Nodes[j]; - - boundElems.push_back(thisBoundFace); - } - } - - /* Sort boundElems in increasing order, where the less than operator - is a comparison between the globalBoundElemID's. */ - sort(boundElems.begin(), boundElems.end()); - - /* Complete the non-blocking sends and synchronize the processors, - because wild cards have been used. */ - SU2_MPI::Waitall(sendReqs.size(), sendReqs.data(), MPI_STATUSES_IGNORE); - - SU2_MPI::Barrier(SU2_MPI::GetComm()); - -#else - /*--- Sequential mode. All boundary elements read must be stored on this - rank. The only information missing is the global ID of the domain - element of the boundary elements. This is created below. ---*/ - for (unsigned long i = 0; i < boundElems.size(); ++i) { - /* Determine the corner nodes and store them in an object of - the class CFaceOfElement to carry out the search in localFaces. */ - CFaceOfElement thisFace(boundElems[i].VTK_Type, boundElems[i].nPolyGrid, boundElems[i].Nodes.data()); - - /* Check if the face is actually present. If not, print an error message - and exit. */ - thisFace.CreateUniqueNumbering(); - vector::iterator low; - low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); - - bool thisFaceFound = false; - if (low != localFaces.end()) { - if (!(thisFace < *low)) thisFaceFound = true; - } - - if (!thisFaceFound) - SU2_MPI::Error("Boundary element not found in list of faces. This is a bug.", CURRENT_FUNCTION); - - /* Set the domain element. */ - boundElems[i].domainElementID = low->elemID0; - } -#endif - - /*--- Allocate space for the local boundary elements and copy the data - from boundElems into bound. ---*/ - nElem_Bound[iMarker] = boundElems.size(); - bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]]; - - for (unsigned long i = 0; i < nElem_Bound[iMarker]; ++i) - bound[iMarker][i] = new CPrimalGridBoundFEM(boundElems[i].globalBoundElemID, boundElems[i].domainElementID, - boundElems[i].VTK_Type, boundElems[i].nPolyGrid, - boundElems[i].nDOFsGrid, boundElems[i].Nodes); - - /*--- Update config information storing the boundary information in the right place ---*/ - Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; - config->SetMarker_All_TagBound(iMarker, Marker_Tag); - config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); - config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); - config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); - config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); - config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); - config->SetMarker_All_Analyze(iMarker, config->GetMarker_CfgFile_Analyze(Marker_Tag)); - config->SetMarker_All_ZoneInterface(iMarker, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag)); - config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); - config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); - config->SetMarker_All_SobolevBC(iMarker, config->GetMarker_CfgFile_SobolevBC(Marker_Tag)); - config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); - config->SetMarker_All_SendRecv(iMarker, NONE); - } - - /* Close the CGNS file again. */ - if (cg_close(fn) != CG_OK) cg_error_exit(); - if (rank == MASTER_NODE) cout << "Successfully closed the CGNS file." << endl; - -#else /* CGNS_VERSION >= 3300 */ - - SU2_MPI::Error("CGNS version 3.3 or higher is necessary for the DG FEM solver", CURRENT_FUNCTION); - -#endif /* CGNS_VERSION >= 3300 */ - -#else /* HAVE_CGNS. */ - - SU2_MPI::Error("SU2 built without CGNS support!!\nTo use CGNS, build SU2 accordingly.", CURRENT_FUNCTION); - -#endif /* HAVE_CGNS. */ -} - void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Initialize the color vector of the elements. ---*/ for (unsigned long i = 0; i < nElem; ++i) elem[i]->SetColor(0); diff --git a/Common/src/fem/meson.build b/Common/src/fem/meson.build index 028f179d6e4..263fccc0e84 100644 --- a/Common/src/fem/meson.build +++ b/Common/src/fem/meson.build @@ -4,5 +4,4 @@ common_src += files(['geometry_structure_fem_part.cpp', 'fem_work_estimate_metis.cpp', 'fem_standard_element.cpp', 'fem_wall_distance.cpp', - 'fem_gauss_jacobi_quadrature.cpp', - 'fem_cgns_elements.cpp']) + 'fem_gauss_jacobi_quadrature.cpp']) diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index ee2c5992c04..6f7f4a0fe98 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -33,6 +33,7 @@ #include "../../include/toolboxes/geometry_toolbox.hpp" #include "../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" #include "../../include/geometry/meshreader/CCGNSMeshReaderFVM.hpp" +#include "../../include/geometry/meshreader/CCGNSMeshReaderFEM.hpp" #include "../../include/geometry/meshreader/CRectangularMeshReaderFVM.hpp" #include "../../include/geometry/meshreader/CBoxMeshReaderFVM.hpp" @@ -3451,7 +3452,8 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena Mesh = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); break; case CGNS_GRID: - Mesh = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) Mesh = new CCGNSMeshReaderFEM(config, val_iZone, val_nZone); + else Mesh = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); break; case RECTANGLE: Mesh = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); diff --git a/Common/src/geometry/meshreader/CCGNSElementType.cpp b/Common/src/geometry/meshreader/CCGNSElementType.cpp new file mode 100644 index 00000000000..8ed50fb91df --- /dev/null +++ b/Common/src/geometry/meshreader/CCGNSElementType.cpp @@ -0,0 +1,840 @@ +/*! + * \file CCGNSElementType.cpp + * \brief Class that converts the CGNS element definitions to the SU2 standard. + * \author E. van der Weide + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#ifdef HAVE_CGNS +#include "../../../include/geometry/meshreader/CCGNSElementType.hpp" +#include "../../../include/option_structure.hpp" + +#include +#include +#include + +using namespace std; + +void CCGNSElementType::CGNSToSU2(const ElementType_t val_elemType, + const unsigned long val_globalID, + const cgsize_t *connCGNS, + std::vector &connSU2) { + + /*--- Clear the contents of connSU2. ---*/ + connSU2.clear(); + + /*--- Search in the stored elements if the current element type is present. ---*/ + unsigned long ind; + for(ind=0; ind SU2ToCGNS; + + switch( val_elemType ) { + + case NODE: CreateDataNODE (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case BAR_2: CreateDataBAR_2 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case BAR_3: CreateDataBAR_3 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case BAR_4: CreateDataBAR_4 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case BAR_5: CreateDataBAR_5 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TRI_3: CreateDataTRI_3 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TRI_6: CreateDataTRI_6 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TRI_10: CreateDataTRI_10 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TRI_15: CreateDataTRI_15 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case QUAD_4: CreateDataQUAD_4 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case QUAD_9: CreateDataQUAD_9 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case QUAD_16: CreateDataQUAD_16 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case QUAD_25: CreateDataQUAD_25 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TETRA_4: CreateDataTETRA_4 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TETRA_10: CreateDataTETRA_10(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TETRA_20: CreateDataTETRA_20(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case TETRA_35: CreateDataTETRA_35(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PYRA_5: CreateDataPYRA_5 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PYRA_14: CreateDataPYRA_14 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PYRA_30: CreateDataPYRA_30 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PYRA_55: CreateDataPYRA_55 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PENTA_6: CreateDataPENTA_6 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PENTA_18: CreateDataPENTA_18(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PENTA_40: CreateDataPENTA_40(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case PENTA_75: CreateDataPENTA_75(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case HEXA_8: CreateDataHEXA_8 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case HEXA_27: CreateDataHEXA_27 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case HEXA_64: CreateDataHEXA_64 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + case HEXA_125: CreateDataHEXA_125(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + + default: + ostringstream message; + message << "CGNS element type " << val_elemType << " not supported."; + SU2_MPI::Error(message.str(), CURRENT_FUNCTION); + } + + /*--- Store the data just created at the end of the corresponding vectors. ---*/ + CGNSTypeStored.push_back(val_elemType); + VTKTypeStored.push_back(VTK_Type); + nPolyStored.push_back(nPoly); + nDOFsStored.push_back(nDOFs); + SU2ToCGNSStored.push_back(SU2ToCGNS); + } + + /*--- Allocate the memory for connSU2 and store the meta data. ---*/ + connSU2.resize(nDOFsStored[ind]+5); + + connSU2[0] = VTKTypeStored[ind]; + connSU2[1] = nPolyStored[ind]; + connSU2[2] = nPolyStored[ind]; + connSU2[3] = nDOFsStored[ind]; + connSU2[4] = val_globalID; + + /*--- Loop over the DOFs and convert the connectivity from CGNS to SU2 + format. Keep in mind that CGNS start the numbering at 1 while + SU2 starts at 0. ---*/ + for(unsigned short i=0; i &SU2ToCGNS) { + + /* Set the required data for a NODE. */ + VTK_Type = VERTEX; + nPoly = 0; + nDOFs = 1; + SU2ToCGNS.push_back(0); +} + +void CCGNSElementType::CreateDataBAR_2(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The BAR_2 element is a linear element. The numbering of the nodes is + the same for CGNS and SU2. */ + VTK_Type = LINE; + nPoly = 1; + nDOFs = 2; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; +} + +void CCGNSElementType::CreateDataBAR_3(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The BAR_3 element is a quadratic element. SU2 numbers to nodes with + increasing parametric value, while in CGNS the internal node is + numbered last. */ + VTK_Type = LINE; + nPoly = 2; + nDOFs = 3; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 2; SU2ToCGNS[2] = 1; +} + +void CCGNSElementType::CreateDataBAR_4(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The BAR_4 element is a cubic element. SU2 numbers to nodes with + increasing parametric value, while in CGNS the internal nodes are + numbered last. */ + VTK_Type = LINE; + nPoly = 3; + nDOFs = 4; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 2; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 1; +} + +void CCGNSElementType::CreateDataBAR_5(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The BAR_5 element is a quartic element. SU2 numbers to nodes with + increasing parametric value, while in CGNS the internal nodes are + numbered last. */ + VTK_Type = LINE; + nPoly = 4; + nDOFs = 5; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 2; SU2ToCGNS[2] = 3; + SU2ToCGNS[3] = 4; SU2ToCGNS[4] = 1; +} + +void CCGNSElementType::CreateDataTRI_3(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TRI_3 element is a linear triangle. The node numbering is the same + in SU2 and CGNS. */ + VTK_Type = TRIANGLE; + nPoly = 1; + nDOFs = 3; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 2; +} + +void CCGNSElementType::CreateDataTRI_6(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TRI_6 element is a quadratic triangle. In CGNS the nodes are numbered + as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes (not present for TRI_6). + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. */ + VTK_Type = TRIANGLE; + nPoly = 2; + nDOFs = 6; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 3; SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 5; SU2ToCGNS[4] = 4; SU2ToCGNS[5] = 2; +} + +void CCGNSElementType::CreateDataTRI_10(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TRI_10 element is a cubic triangle. In CGNS the nodes are numbered + as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. */ + VTK_Type = TRIANGLE; + nPoly = 3; + nDOFs = 10; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 3; SU2ToCGNS[2] = 4; SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 8; SU2ToCGNS[5] = 9; SU2ToCGNS[6] = 5; SU2ToCGNS[7] = 7; + SU2ToCGNS[8] = 6; SU2ToCGNS[9] = 2; +} + +void CCGNSElementType::CreateDataTRI_15(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TRI_15 element is a quartic triangle. In CGNS the nodes are numbered + as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. + Also note that in the CGNS standard the face nodes are not placed at + the location for uniform spacing. This effect is currently ignored, + i.e. it is assumed that the spacing in parameter space is uniform. */ + VTK_Type = TRIANGLE; + nPoly = 4; + nDOFs = 15; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 3; SU2ToCGNS[2] = 4; SU2ToCGNS[3] = 5; + SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 11; SU2ToCGNS[6] = 12; SU2ToCGNS[7] = 13; + SU2ToCGNS[8] = 6; SU2ToCGNS[9] = 10; SU2ToCGNS[10] = 14; SU2ToCGNS[11] = 7; + SU2ToCGNS[12] = 9; SU2ToCGNS[13] = 8; SU2ToCGNS[14] = 2; +} + +void CCGNSElementType::CreateDataQUAD_4(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The QUAD_4 element is a linear quadrilateral. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes (not present for QUAD_4). + - Third the face nodes (not present for QUAD_4). + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. */ + VTK_Type = QUADRILATERAL; + nPoly = 1; + nDOFs = 4; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 2; +} + +void CCGNSElementType::CreateDataQUAD_9(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The QUAD_9 element is a quadratic quadrilateral. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. */ + VTK_Type = QUADRILATERAL; + nPoly = 2; + nDOFs = 9; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 7; + SU2ToCGNS[4] = 8; SU2ToCGNS[5] = 5; SU2ToCGNS[6] = 3; SU2ToCGNS[7] = 6; + SU2ToCGNS[8] = 2; +} + +void CCGNSElementType::CreateDataQUAD_16(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The QUAD_16 element is a cubic quadrilateral. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. */ + VTK_Type = QUADRILATERAL; + nPoly = 3; + nDOFs = 16; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 11; SU2ToCGNS[5] = 12; SU2ToCGNS[6] = 13; SU2ToCGNS[7] = 6; + SU2ToCGNS[8] = 10; SU2ToCGNS[9] = 15; SU2ToCGNS[10] = 14; SU2ToCGNS[11] = 7; + SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 9; SU2ToCGNS[14] = 8; SU2ToCGNS[15] = 2; +} + +void CCGNSElementType::CreateDataQUAD_25(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The QUAD_25 element is a quartic quadrilateral. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + In SU2 the node numbering takes place along increasing i- and j-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the other edge. */ + VTK_Type = QUADRILATERAL; + nPoly = 4; + nDOFs = 25; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 6; + SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 15; SU2ToCGNS[6] = 16; SU2ToCGNS[7] = 17; + SU2ToCGNS[8] = 18; SU2ToCGNS[9] = 7; SU2ToCGNS[10] = 14; SU2ToCGNS[11] = 23; + SU2ToCGNS[12] = 24; SU2ToCGNS[13] = 19; SU2ToCGNS[14] = 8; SU2ToCGNS[15] = 13; + SU2ToCGNS[16] = 22; SU2ToCGNS[17] = 21; SU2ToCGNS[18] = 20; SU2ToCGNS[19] = 9; + SU2ToCGNS[20] = 3; SU2ToCGNS[21] = 12; SU2ToCGNS[22] = 11; SU2ToCGNS[23] = 10; + SU2ToCGNS[24] = 2; +} + +void CCGNSElementType::CreateDataTETRA_4(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TETRA_4 element is a linear tetrahedron. The node numbering is + the same in SU2 and CGNS. */ + VTK_Type = TETRAHEDRON; + nPoly = 1; + nDOFs = 4; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 2; SU2ToCGNS[3] = 3; +} + +void CCGNSElementType::CreateDataTETRA_10(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TETRA_10 element is a quadratic tetrahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes (not present in TETRA_10). + - Fourth the volume nodes (not present in TETRA_10). + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = TETRAHEDRON; + nPoly = 2; + nDOFs = 10; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 6; + SU2ToCGNS[4] = 5; SU2ToCGNS[5] = 2; SU2ToCGNS[6] = 7; SU2ToCGNS[7] = 8; + SU2ToCGNS[8] = 9; SU2ToCGNS[9] = 3; +} + +void CCGNSElementType::CreateDataTETRA_20(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TETRA_20 element is a cubic tetrahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes (not present in TETRA_20). + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = TETRAHEDRON; + nPoly = 3; + nDOFs = 20; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 9; SU2ToCGNS[5] = 16; SU2ToCGNS[6] = 6; SU2ToCGNS[7] = 8; + SU2ToCGNS[8] = 7; SU2ToCGNS[9] = 2; SU2ToCGNS[10] = 10; SU2ToCGNS[11] = 17; + SU2ToCGNS[12] = 12; SU2ToCGNS[13] = 19; SU2ToCGNS[14] = 18; SU2ToCGNS[15] = 14; + SU2ToCGNS[16] = 11; SU2ToCGNS[17] = 13; SU2ToCGNS[18] = 15; SU2ToCGNS[19] = 3; +} + +void CCGNSElementType::CreateDataTETRA_35(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The TETRA_35 element is a quartic tetrahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. Also note that in the CGNS standard the face and volume + nodes are not placed at the location for uniform spacing. This effect is + currently ignored, i.e. it is assumed that the spacing in parameter space + is uniform. */ + VTK_Type = TETRAHEDRON; + nPoly = 4; + nDOFs = 35; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 6; + SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 12; SU2ToCGNS[6] = 22; SU2ToCGNS[7] = 23; + SU2ToCGNS[8] = 7; SU2ToCGNS[9] = 11; SU2ToCGNS[10] = 24; SU2ToCGNS[11] = 8; + SU2ToCGNS[12] = 10; SU2ToCGNS[13] = 9; SU2ToCGNS[14] = 2; SU2ToCGNS[15] = 13; + SU2ToCGNS[16] = 25; SU2ToCGNS[17] = 26; SU2ToCGNS[18] = 16; SU2ToCGNS[19] = 32; + SU2ToCGNS[20] = 34; SU2ToCGNS[21] = 28; SU2ToCGNS[22] = 31; SU2ToCGNS[23] = 29; + SU2ToCGNS[24] = 19; SU2ToCGNS[25] = 14; SU2ToCGNS[26] = 27; SU2ToCGNS[27] = 17; + SU2ToCGNS[28] = 33; SU2ToCGNS[29] = 30; SU2ToCGNS[30] = 20; SU2ToCGNS[31] = 15; + SU2ToCGNS[32] = 18; SU2ToCGNS[33] = 21; SU2ToCGNS[34] = 3; +} + +void CCGNSElementType::CreateDataPYRA_5(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PYRA_5 element is a linear pyramid. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes (not present in PYRA_5). + - Third the face nodes (not present in PYRA_5). + - Fourth the volume nodes (not present in PYRA_5). + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = PYRAMID; + nPoly = 1; + nDOFs = 5; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 2; + SU2ToCGNS[4] = 4; +} + +void CCGNSElementType::CreateDataPYRA_14(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PYRA_14 element is a quadratic pyramid. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes (not present in PYRA_14). + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = PYRAMID; + nPoly = 2; + nDOFs = 14; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 5; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 8; + SU2ToCGNS[4] = 13; SU2ToCGNS[5] = 6; SU2ToCGNS[6] = 3; SU2ToCGNS[7] = 7; + SU2ToCGNS[8] = 2; SU2ToCGNS[9] = 9; SU2ToCGNS[10] = 10; SU2ToCGNS[11] = 12; + SU2ToCGNS[12] = 11; SU2ToCGNS[13] = 4; +} + +void CCGNSElementType::CreateDataPYRA_30(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PYRA_30 element is a cubic pyramid. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = PYRAMID; + nPoly = 3; + nDOFs = 30; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 5; SU2ToCGNS[2] = 6; SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 12; SU2ToCGNS[5] = 21; SU2ToCGNS[6] = 22; SU2ToCGNS[7] = 7; + SU2ToCGNS[8] = 11; SU2ToCGNS[9] = 24; SU2ToCGNS[10] = 23; SU2ToCGNS[11] = 8; + SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 10; SU2ToCGNS[14] = 9; SU2ToCGNS[15] = 2; + SU2ToCGNS[16] = 13; SU2ToCGNS[17] = 25; SU2ToCGNS[18] = 15; SU2ToCGNS[19] = 28; + SU2ToCGNS[20] = 29; SU2ToCGNS[21] = 26; SU2ToCGNS[22] = 19; SU2ToCGNS[23] = 27; + SU2ToCGNS[24] = 17; SU2ToCGNS[25] = 14; SU2ToCGNS[26] = 16; SU2ToCGNS[27] = 20; + SU2ToCGNS[28] = 18; SU2ToCGNS[29] = 4; +} + +void CCGNSElementType::CreateDataPYRA_55(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PYRA_55 element is a quartic pyramid. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. Also note that in the CGNS standard the triangular face + and volume nodes are not placed at the location for uniform spacing. This + effect is currently ignored, i.e. it is assumed that the spacing in + parameter space is uniform.*/ + VTK_Type = PYRAMID; + nPoly = 4; + nDOFs = 55; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 5; SU2ToCGNS[2] = 6; SU2ToCGNS[3] = 7; + SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 16; SU2ToCGNS[6] = 29; SU2ToCGNS[7] = 30; + SU2ToCGNS[8] = 31; SU2ToCGNS[9] = 8; SU2ToCGNS[10] = 15; SU2ToCGNS[11] = 36; + SU2ToCGNS[12] = 37; SU2ToCGNS[13] = 32; SU2ToCGNS[14] = 9; SU2ToCGNS[15] = 14; + SU2ToCGNS[16] = 35; SU2ToCGNS[17] = 34; SU2ToCGNS[18] = 33; SU2ToCGNS[19] = 10; + SU2ToCGNS[20] = 3; SU2ToCGNS[21] = 13; SU2ToCGNS[22] = 12; SU2ToCGNS[23] = 11; + SU2ToCGNS[24] = 2; SU2ToCGNS[25] = 17; SU2ToCGNS[26] = 38; SU2ToCGNS[27] = 39; + SU2ToCGNS[28] = 20; SU2ToCGNS[29] = 48; SU2ToCGNS[30] = 50; SU2ToCGNS[31] = 51; + SU2ToCGNS[32] = 41; SU2ToCGNS[33] = 47; SU2ToCGNS[34] = 53; SU2ToCGNS[35] = 52; + SU2ToCGNS[36] = 42; SU2ToCGNS[37] = 26; SU2ToCGNS[38] = 45; SU2ToCGNS[39] = 44; + SU2ToCGNS[40] = 23; SU2ToCGNS[41] = 18; SU2ToCGNS[42] = 40; SU2ToCGNS[43] = 21; + SU2ToCGNS[44] = 49; SU2ToCGNS[45] = 54; SU2ToCGNS[46] = 43; SU2ToCGNS[47] = 27; + SU2ToCGNS[48] = 46; SU2ToCGNS[49] = 24; SU2ToCGNS[50] = 19; SU2ToCGNS[51] = 22; + SU2ToCGNS[52] = 28; SU2ToCGNS[53] = 25; SU2ToCGNS[54] = 4; +} + +void CCGNSElementType::CreateDataPENTA_6(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PENTA_6 element is a linear prism. The node numbering is + the same in SU2 and CGNS. */ + VTK_Type = PRISM; + nPoly = 1; + nDOFs = 6; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 2; + SU2ToCGNS[3] = 3; SU2ToCGNS[4] = 4; SU2ToCGNS[5] = 5; +} + +void CCGNSElementType::CreateDataPENTA_18(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PENTA_18 element is a quadratic prism. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes (not present in PENTA_18). + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = PRISM; + nPoly = 2; + nDOFs = 18; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 6; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 8; + SU2ToCGNS[4] = 7; SU2ToCGNS[5] = 2; SU2ToCGNS[6] = 9; SU2ToCGNS[7] = 15; + SU2ToCGNS[8] = 10; SU2ToCGNS[9] = 17; SU2ToCGNS[10] = 16; SU2ToCGNS[11] = 11; + SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 12; SU2ToCGNS[14] = 4; SU2ToCGNS[15] = 14; + SU2ToCGNS[16] = 13; SU2ToCGNS[17] = 5; +} + +void CCGNSElementType::CreateDataPENTA_40(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PENTA_40 element is a cubic prism. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = PRISM; + nPoly = 3; + nDOFs = 40; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 6; SU2ToCGNS[2] = 7; SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 11; SU2ToCGNS[5] = 24; SU2ToCGNS[6] = 8; SU2ToCGNS[7] = 10; + SU2ToCGNS[8] = 9; SU2ToCGNS[9] = 2; SU2ToCGNS[10] = 12; SU2ToCGNS[11] = 25; + SU2ToCGNS[12] = 26; SU2ToCGNS[13] = 14; SU2ToCGNS[14] = 34; SU2ToCGNS[15] = 38; + SU2ToCGNS[16] = 29; SU2ToCGNS[17] = 33; SU2ToCGNS[18] = 30; SU2ToCGNS[19] = 16; + SU2ToCGNS[20] = 13; SU2ToCGNS[21] = 28; SU2ToCGNS[22] = 27; SU2ToCGNS[23] = 15; + SU2ToCGNS[24] = 35; SU2ToCGNS[25] = 39; SU2ToCGNS[26] = 32; SU2ToCGNS[27] = 36; + SU2ToCGNS[28] = 31; SU2ToCGNS[29] = 17; SU2ToCGNS[30] = 3; SU2ToCGNS[31] = 18; + SU2ToCGNS[32] = 19; SU2ToCGNS[33] = 4; SU2ToCGNS[34] = 23; SU2ToCGNS[35] = 37; + SU2ToCGNS[36] = 20; SU2ToCGNS[37] = 22; SU2ToCGNS[38] = 21; SU2ToCGNS[39] = 5; +} + +void CCGNSElementType::CreateDataPENTA_75(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The PENTA_75 element is a quartic prism. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. Also note that in the CGNS standard the triangular face + and volume nodes are not placed at the location for uniform spacing. This + effect is currently ignored, i.e. it is assumed that the spacing in + parameter space is uniform. */ + VTK_Type = PRISM; + nPoly = 4; + nDOFs = 75; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 6; SU2ToCGNS[2] = 7; SU2ToCGNS[3] = 8; + SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 14; SU2ToCGNS[6] = 33; SU2ToCGNS[7] = 34; + SU2ToCGNS[8] = 9; SU2ToCGNS[9] = 13; SU2ToCGNS[10] = 35; SU2ToCGNS[11] = 10; + SU2ToCGNS[12] = 12; SU2ToCGNS[13] = 11; SU2ToCGNS[14] = 2; SU2ToCGNS[15] = 15; + SU2ToCGNS[16] = 36; SU2ToCGNS[17] = 37; SU2ToCGNS[18] = 38; SU2ToCGNS[19] = 18; + SU2ToCGNS[20] = 56; SU2ToCGNS[21] = 66; SU2ToCGNS[22] = 67; SU2ToCGNS[23] = 45; + SU2ToCGNS[24] = 55; SU2ToCGNS[25] = 68; SU2ToCGNS[26] = 46; SU2ToCGNS[27] = 54; + SU2ToCGNS[28] = 47; SU2ToCGNS[29] = 21; SU2ToCGNS[30] = 16; SU2ToCGNS[31] = 43; + SU2ToCGNS[32] = 44; SU2ToCGNS[33] = 39; SU2ToCGNS[34] = 19; SU2ToCGNS[35] = 57; + SU2ToCGNS[36] = 69; SU2ToCGNS[37] = 70; SU2ToCGNS[38] = 52; SU2ToCGNS[39] = 62; + SU2ToCGNS[40] = 71; SU2ToCGNS[41] = 53; SU2ToCGNS[42] = 61; SU2ToCGNS[43] = 48; + SU2ToCGNS[44] = 22; SU2ToCGNS[45] = 17; SU2ToCGNS[46] = 42; SU2ToCGNS[47] = 41; + SU2ToCGNS[48] = 40; SU2ToCGNS[49] = 20; SU2ToCGNS[50] = 58; SU2ToCGNS[51] = 72; + SU2ToCGNS[52] = 73; SU2ToCGNS[53] = 51; SU2ToCGNS[54] = 59; SU2ToCGNS[55] = 74; + SU2ToCGNS[56] = 50; SU2ToCGNS[57] = 60; SU2ToCGNS[58] = 49; SU2ToCGNS[59] = 23; + SU2ToCGNS[60] = 3; SU2ToCGNS[61] = 24; SU2ToCGNS[62] = 25; SU2ToCGNS[63] = 26; + SU2ToCGNS[64] = 4; SU2ToCGNS[65] = 32; SU2ToCGNS[66] = 63; SU2ToCGNS[67] = 64; + SU2ToCGNS[68] = 27; SU2ToCGNS[69] = 31; SU2ToCGNS[70] = 65; SU2ToCGNS[71] = 28; + SU2ToCGNS[72] = 30; SU2ToCGNS[73] = 29; SU2ToCGNS[74] = 5; +} + +void CCGNSElementType::CreateDataHEXA_8(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The HEXA_8 element is a linear hexahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes (not present in HEXA_8). + - Third the face nodes (not present in HEXA_8). + - Fourth the volume nodes (not present in HEXA_8). + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = HEXAHEDRON; + nPoly = 1; + nDOFs = 8; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 2; + SU2ToCGNS[4] = 4; SU2ToCGNS[5] = 5; SU2ToCGNS[6] = 7; SU2ToCGNS[7] = 6; +} + +void CCGNSElementType::CreateDataHEXA_27(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The HEXA_27 element is a quadratic hexahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = HEXAHEDRON; + nPoly = 2; + nDOFs = 27; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 8; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 11; + SU2ToCGNS[4] = 20; SU2ToCGNS[5] = 9; SU2ToCGNS[6] = 3; SU2ToCGNS[7] = 10; + SU2ToCGNS[8] = 2; SU2ToCGNS[9] = 12; SU2ToCGNS[10] = 21; SU2ToCGNS[11] = 13; + SU2ToCGNS[12] = 24; SU2ToCGNS[13] = 26; SU2ToCGNS[14] = 22; SU2ToCGNS[15] = 15; + SU2ToCGNS[16] = 23; SU2ToCGNS[17] = 14; SU2ToCGNS[18] = 4; SU2ToCGNS[19] = 16; + SU2ToCGNS[20] = 5; SU2ToCGNS[21] = 19; SU2ToCGNS[22] = 25; SU2ToCGNS[23] = 17; + SU2ToCGNS[24] = 7; SU2ToCGNS[25] = 18; SU2ToCGNS[26] = 6; +} + +void CCGNSElementType::CreateDataHEXA_64(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The HEXA_64 element is a cubic hexahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = HEXAHEDRON; + nPoly = 3; + nDOFs = 64; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 8; SU2ToCGNS[2] = 9; SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 15; SU2ToCGNS[5] = 32; SU2ToCGNS[6] = 33; SU2ToCGNS[7] = 10; + SU2ToCGNS[8] = 14; SU2ToCGNS[9] = 35; SU2ToCGNS[10] = 34; SU2ToCGNS[11] = 11; + SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 13; SU2ToCGNS[14] = 12; SU2ToCGNS[15] = 2; + SU2ToCGNS[16] = 16; SU2ToCGNS[17] = 36; SU2ToCGNS[18] = 37; SU2ToCGNS[19] = 18; + SU2ToCGNS[20] = 49; SU2ToCGNS[21] = 56; SU2ToCGNS[22] = 57; SU2ToCGNS[23] = 40; + SU2ToCGNS[24] = 48; SU2ToCGNS[25] = 59; SU2ToCGNS[26] = 58; SU2ToCGNS[27] = 41; + SU2ToCGNS[28] = 22; SU2ToCGNS[29] = 45; SU2ToCGNS[30] = 44; SU2ToCGNS[31] = 20; + SU2ToCGNS[32] = 17; SU2ToCGNS[33] = 39; SU2ToCGNS[34] = 38; SU2ToCGNS[35] = 19; + SU2ToCGNS[36] = 50; SU2ToCGNS[37] = 60; SU2ToCGNS[38] = 61; SU2ToCGNS[39] = 43; + SU2ToCGNS[40] = 51; SU2ToCGNS[41] = 63; SU2ToCGNS[42] = 62; SU2ToCGNS[43] = 42; + SU2ToCGNS[44] = 23; SU2ToCGNS[45] = 46; SU2ToCGNS[46] = 47; SU2ToCGNS[47] = 21; + SU2ToCGNS[48] = 4; SU2ToCGNS[49] = 24; SU2ToCGNS[50] = 25; SU2ToCGNS[51] = 5; + SU2ToCGNS[52] = 31; SU2ToCGNS[53] = 52; SU2ToCGNS[54] = 53; SU2ToCGNS[55] = 26; + SU2ToCGNS[56] = 30; SU2ToCGNS[57] = 55; SU2ToCGNS[58] = 54; SU2ToCGNS[59] = 27; + SU2ToCGNS[60] = 7; SU2ToCGNS[61] = 29; SU2ToCGNS[62] = 28; SU2ToCGNS[63] = 6; +} + +void CCGNSElementType::CreateDataHEXA_125(unsigned short &VTK_Type, + unsigned short &nPoly, + unsigned short &nDOFs, + vector &SU2ToCGNS) { + + /* The HEXA_125 element is a quartic hexahedron. In CGNS the nodes are + numbered as follows: - First the vertex nodes. + - Second the edge nodes. + - Third the face nodes. + - Fourth the volume nodes. + In SU2 the node numbering takes place along increasing i-, j- and k-lines, + where the i-direction is defined from node 0 to 1 and the j-direction + from node 0 along the second edge and the k-direction from node 0 along + the third edge. */ + VTK_Type = HEXAHEDRON; + nPoly = 4; + nDOFs = 125; + + SU2ToCGNS.resize(nDOFs); + SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 8; SU2ToCGNS[2] = 9; SU2ToCGNS[3] = 10; SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 19; SU2ToCGNS[6] = 44; SU2ToCGNS[7] = 45; SU2ToCGNS[8] = 46; SU2ToCGNS[9] = 11; + SU2ToCGNS[10] = 18; SU2ToCGNS[11] = 51; SU2ToCGNS[12] = 52; SU2ToCGNS[13] = 47; SU2ToCGNS[14] = 12; + SU2ToCGNS[15] = 17; SU2ToCGNS[16] = 50; SU2ToCGNS[17] = 49; SU2ToCGNS[18] = 48; SU2ToCGNS[19] = 13; + SU2ToCGNS[20] = 3; SU2ToCGNS[21] = 16; SU2ToCGNS[22] = 15; SU2ToCGNS[23] = 14; SU2ToCGNS[24] = 2; + SU2ToCGNS[25] = 20; SU2ToCGNS[26] = 53; SU2ToCGNS[27] = 54; SU2ToCGNS[28] = 55; SU2ToCGNS[29] = 23; + SU2ToCGNS[30] = 82; SU2ToCGNS[31] = 98; SU2ToCGNS[32] = 99; SU2ToCGNS[33] = 100; SU2ToCGNS[34] = 62; + SU2ToCGNS[35] = 81; SU2ToCGNS[36] = 105; SU2ToCGNS[37] = 106; SU2ToCGNS[38] = 101; SU2ToCGNS[39] = 63; + SU2ToCGNS[40] = 80; SU2ToCGNS[41] = 104; SU2ToCGNS[42] = 103; SU2ToCGNS[43] = 102; SU2ToCGNS[44] = 64; + SU2ToCGNS[45] = 29; SU2ToCGNS[46] = 73; SU2ToCGNS[47] = 72; SU2ToCGNS[48] = 71; SU2ToCGNS[49] = 26; + SU2ToCGNS[50] = 21; SU2ToCGNS[51] = 60; SU2ToCGNS[52] = 61; SU2ToCGNS[53] = 56; SU2ToCGNS[54] = 24; + SU2ToCGNS[55] = 83; SU2ToCGNS[56] = 107; SU2ToCGNS[57] = 108; SU2ToCGNS[58] = 109; SU2ToCGNS[59] = 69; + SU2ToCGNS[60] = 88; SU2ToCGNS[61] = 114; SU2ToCGNS[62] = 115; SU2ToCGNS[63] = 110; SU2ToCGNS[64] = 70; + SU2ToCGNS[65] = 87; SU2ToCGNS[66] = 113; SU2ToCGNS[67] = 112; SU2ToCGNS[68] = 111; SU2ToCGNS[69] = 65; + SU2ToCGNS[70] = 30; SU2ToCGNS[71] = 74; SU2ToCGNS[72] = 79; SU2ToCGNS[73] = 78; SU2ToCGNS[74] = 27; + SU2ToCGNS[75] = 22; SU2ToCGNS[76] = 59; SU2ToCGNS[77] = 58; SU2ToCGNS[78] = 57; SU2ToCGNS[79] = 25; + SU2ToCGNS[80] = 84; SU2ToCGNS[81] = 116; SU2ToCGNS[82] = 117; SU2ToCGNS[83] = 118; SU2ToCGNS[84] = 68; + SU2ToCGNS[85] = 85; SU2ToCGNS[86] = 123; SU2ToCGNS[87] = 124; SU2ToCGNS[88] = 119; SU2ToCGNS[89] = 67; + SU2ToCGNS[90] = 86; SU2ToCGNS[91] = 122; SU2ToCGNS[92] = 121; SU2ToCGNS[93] = 120; SU2ToCGNS[94] = 66; + SU2ToCGNS[95] = 31; SU2ToCGNS[96] = 75; SU2ToCGNS[97] = 76; SU2ToCGNS[98] = 77; SU2ToCGNS[99] = 28; + SU2ToCGNS[100] = 4; SU2ToCGNS[101] = 32; SU2ToCGNS[102] = 33; SU2ToCGNS[103] = 34; SU2ToCGNS[104] = 5; + SU2ToCGNS[105] = 43; SU2ToCGNS[106] = 89; SU2ToCGNS[107] = 90; SU2ToCGNS[108] = 91; SU2ToCGNS[109] = 35; + SU2ToCGNS[110] = 42; SU2ToCGNS[111] = 96; SU2ToCGNS[112] = 97; SU2ToCGNS[113] = 92; SU2ToCGNS[114] = 36; + SU2ToCGNS[115] = 41; SU2ToCGNS[116] = 95; SU2ToCGNS[117] = 94; SU2ToCGNS[118] = 93; SU2ToCGNS[119] = 37; + SU2ToCGNS[120] = 7; SU2ToCGNS[121] = 40; SU2ToCGNS[122] = 39; SU2ToCGNS[123] = 38; SU2ToCGNS[124] = 6; +} + +#endif diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp new file mode 100644 index 00000000000..9f527b4e6cc --- /dev/null +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -0,0 +1,550 @@ +/*! + * \file CCGNSMeshReaderFEM.cpp + * \brief Class that reads a single zone of a CGNS mesh file from disk into + * linear partitions across all ranks. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#include "../../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../../include/geometry/meshreader/CCGNSMeshReaderFEM.hpp" +#include "../../../include/geometry/meshreader/CCGNSElementType.hpp" + +CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) + : CCGNSMeshReaderBase(val_config, val_iZone, val_nZone) { +#ifdef HAVE_CGNS + OpenCGNSFile(config->GetMesh_FileName()); + + /*--- Read the basic information about the database and zone(s). ---*/ + ReadCGNSDatabaseMetadata(); + ReadCGNSZoneMetadata(); + + /*--- Read the volume connectivity and distribute it + linearly over the MPI ranks. ---*/ + ReadCGNSVolumeElementConnectivity(); + + /*--- Read the coordinates of the points and communicate the ones that + are needed on this MPI rank. ---*/ + ReadCGNSPointCoordinates(); + CommPointCoordinates(); + + /*--- Read the surface connectivity and store the surface elements whose + corresponding volume element is stored on this MPI rank. ---*/ + ReadCGNSSurfaceElementConnectivity(); + + /*--- We have extracted all CGNS data. Close the CGNS file. ---*/ + if (cg_close(cgnsFileID)) cg_error_exit(); + +#else + SU2_MPI::Error(string(" SU2 built without CGNS support. \n") + string(" To use CGNS, build SU2 accordingly."), + CURRENT_FUNCTION); +#endif +} + +CCGNSMeshReaderFEM::~CCGNSMeshReaderFEM() = default; + +#ifdef HAVE_CGNS +void CCGNSMeshReaderFEM::ReadCGNSConnectivityRangeSection(const int val_section, + const unsigned long val_firstIndex, + const unsigned long val_lastIndex, + unsigned long &elemCount, + unsigned long &localElemCount, + vector &localConn) { + + /*--- Read the connectivity details for this section. ---*/ + int nbndry, parent_flag; + cgsize_t startE, endE; + ElementType_t elemType; + char sectionName[CGNS_STRING_SIZE]; + + if(cg_section_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, sectionName, + &elemType, &startE, &endE, &nbndry, &parent_flag)) + cg_error_exit(); + + /*--- Determine the number of elements in this section and update + the element counters accordingly. ---*/ + const unsigned long nElemSection = (endE-startE+1); + const unsigned long elemCountOld = elemCount; + elemCount += nElemSection; + + /*--- Check for overlap with the element range this rank is responsible for. ---*/ + const unsigned long indBegOverlap = max(elemCountOld, val_firstIndex); + const unsigned long indEndOverlap = min(elemCount, val_lastIndex); + + if(indEndOverlap > indBegOverlap) { + + /*--- This rank must read element data from this connectivity section. + Determine the offset relative to the start of this section and + the number of elements to be read by this rank. ---*/ + const unsigned long offsetRank = indBegOverlap - elemCountOld; + const unsigned long nElemRank = indEndOverlap - indBegOverlap; + nElems[val_section] = nElemRank; + + /*--- Determine the index range to be read for this rank. ---*/ + const cgsize_t iBeg = startE + offsetRank; + const cgsize_t iEnd = iBeg + nElemRank -1; + + /*--- Determine the size of the vector needed to read + the connectivity data from the CGNS file. ---*/ + cgsize_t sizeNeeded; + if (cg_ElementPartialSize(cgnsFileID, cgnsBase, cgnsZone, val_section+1, + iBeg, iEnd, &sizeNeeded) != CG_OK) + cg_error_exit(); + + /*--- Allocate the memory for the connectivity and read the data. ---*/ + vector connCGNSVec(sizeNeeded); + if (elemType == MIXED) { + vector connCGNSOffsetVec(iEnd-iBeg+2); + if(cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, + iBeg, iEnd, connCGNSVec.data(), + connCGNSOffsetVec.data(), NULL) != CG_OK) + cg_error_exit(); + + } else { + if(cg_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, + iBeg, iEnd, connCGNSVec.data(), NULL) != CG_OK) + cg_error_exit(); + } + + /*--- Define the variables needed for the conversion of the CGNS + format to the SU2 internal format. ---*/ + CCGNSElementType CGNSElem; + std::vector connSU2; + ElementType_t typeElem = elemType; + const cgsize_t *connCGNS = connCGNSVec.data(); + + /*--- Loop over the elements just read. ---*/ + for(unsigned long i=0; i SINGLE_NODE) + cout << "Loading volume elements into linear partitions." << endl; + else + cout << "Loading volume elements." << endl; + } + + /*--- Get a partitioner to help with linear partitioning. ---*/ + CLinearPartitioner elemPartitioner(numberOfGlobalElements,0); + + /*--- Determine the index of the first and last element to be stored + on this rank and the number of local elements. ---*/ + const unsigned long firstIndex = elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long lastIndex = elemPartitioner.GetLastIndexOnRank(rank); + numberOfLocalElements = elemPartitioner.GetSizeOnRank(rank); + + /*--- Loop over the section and check for a section with volume elements. ---*/ + unsigned long elemCount = 0, localElemCount = 0; + for(int s=0; s localFaces; + DetermineFacesVolumeElements(localFaces); + + /*--- Determine the number of markers. ---*/ + numberOfMarkers = 0; + for (int s = 0; s < nSections; s++) + if (!isInterior[s]) ++numberOfMarkers; + + /*--- Allocate the memory for the number of markers and local surface elements. + Also allocate the first index of surfaceElementConnectivity. ---*/ + markerNames.resize(numberOfMarkers); + numberOfLocalSurfaceElements.resize(numberOfMarkers); + surfaceElementConnectivity.resize(numberOfMarkers); + + /*--- Loop over the number of sections and check for a surface. ---*/ + int markerCount = 0; + for(int s=0; s &localFaces, + unsigned long &nSurfElem, + vector &surfConn) { + + /*--- Initialize nSurfElem to zero. ---*/ + nSurfElem = 0; + + /*--- Read the connectivity details for this section and determine the number + of elements present in this section. ---*/ + int nbndry, parent_flag; + cgsize_t startE, endE; + ElementType_t elemType; + char sectionName[CGNS_STRING_SIZE]; + + if(cg_section_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, sectionName, + &elemType, &startE, &endE, &nbndry, &parent_flag)) + cg_error_exit(); + + const unsigned long nElemSection = (endE-startE+1); + + /*--- Determine the number of chunks used for the reading of the surface + elements. This is done to avoid a memory bottleneck for extremely + big cases. For reasonably sized grids this connectivity can be + read in a single call. ---*/ + unsigned long nChunks = nElemSection/localFaces.size(); + if(nChunks*localFaces.size() != nElemSection) ++nChunks; + const unsigned long nElemChunk = nElemSection/nChunks; + + /*--- Loop over the number of chunks. ---*/ + for(unsigned long iChunk=0; iChunk connCGNSVec(sizeNeeded); + if (elemType == MIXED) { + vector connCGNSOffsetVec(iEnd-iBeg+2); + if(cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, + iBeg, iEnd, connCGNSVec.data(), + connCGNSOffsetVec.data(), NULL) != CG_OK) + cg_error_exit(); + + } else { + if(cg_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, + iBeg, iEnd, connCGNSVec.data(), NULL) != CG_OK) + cg_error_exit(); + } + + /*--- Define the variables needed for the conversion of the CGNS + format to the SU2 internal format. ---*/ + CCGNSElementType CGNSElem; + std::vector connSU2; + ElementType_t typeElem = elemType; + const cgsize_t *connCGNS = connCGNSVec.data(); + + /*--- Loop over the elements just read. ---*/ + for(cgsize_t i=iBeg; i<=iEnd; ++i) { + + /*--- Determine the element type for this element if this is a mixed + connectivity and set the pointer to the actual connectivity data. ---*/ + if(elemType == MIXED) { + typeElem = (ElementType_t) connCGNS[0]; + ++connCGNS; + } + + /*--- Convert the CGNS connectivity to SU2 connectivity and update + the pointer for the next surface element. ---*/ + const unsigned long globalID = i-1; + CGNSElem.CGNSToSU2(typeElem, globalID, connCGNS, connSU2); + connCGNS += connSU2[3]; + + /*--- Easier storage of the VTK type, polynomial degree + and number of DOFs of the surface element. ---*/ + const unsigned short VTK_Type = (unsigned short) connSU2[0]; + const unsigned short nPolyGrid = (unsigned short) connSU2[1]; + const unsigned short nDOFsGrid = (unsigned short) connSU2[3]; + + /*--- Make a distinction between the possible element surface types and + determine the corner points in local numbering of the element. ---*/ + const unsigned short nDOFEdgeGrid = nPolyGrid + 1; + + CFaceOfElement thisFace; + thisFace.cornerPoints[0] = 0; thisFace.cornerPoints[1] = nPolyGrid; + + switch( VTK_Type ) { + case LINE: + thisFace.nCornerPoints = 2; + break; + + case TRIANGLE: + thisFace.nCornerPoints = 3; + thisFace.cornerPoints[2] = nDOFsGrid -1; + break; + + case QUADRILATERAL: + thisFace.nCornerPoints = 4; + thisFace.cornerPoints[2] = nPolyGrid*nDOFEdgeGrid; + thisFace.cornerPoints[3] = nDOFsGrid -1; + break; + + default: + ostringstream message; + message << "Unsupported FEM boundary element value, " << typeElem + << ", in surface section " << sectionName; + SU2_MPI::Error(message.str(), CURRENT_FUNCTION); + } + + /*--- Convert the local numbering of thisFace to global numbering + and create a unique numbering of corner points. ---*/ + for(unsigned short j=0; j::const_iterator low; + low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); + if(low != localFaces.end()) { + if( !(thisFace < *low) ) { + + /*--- Update the number of local surface elements. ---*/ + ++nSurfElem; + + /*--- Store the meta data in the first 5 locations of connSU2. ---*/ + connSU2[0] = VTK_Type; + connSU2[1] = nPolyGrid; + connSU2[2] = nDOFsGrid; + connSU2[3] = globalID; // Global surface elem ID. + connSU2[4] = low->elemID0; // Global volume elem ID. + + /*--- Store the connectivity data in surfConn. ---*/ + surfConn.insert(surfConn.end(), connSU2.begin(), connSU2.end()); + } + } + } + } +} +#endif + +void CCGNSMeshReaderFEM::CommPointCoordinates(void) { + + /*--- Determine the linear partitioning of the points. ---*/ + CLinearPartitioner pointPartitioner(numberOfGlobalPoints,0); + + /*--- Loop over the local elements to determine the global + point IDs to be stored on this rank. --*/ + unsigned long ind = 0; + for(unsigned long i=0; i::iterator lastNode; + lastNode = unique(globalPointIDs.begin(), globalPointIDs.end()); + globalPointIDs.erase(lastNode, globalPointIDs.end()); + + /*--- Determine the number of locally stored points. ---*/ + numberOfLocalPoints = globalPointIDs.size(); + + /*--- This rest of this function only needs to done when MPI is used. ---*/ +#ifdef HAVE_MPI + + /*--- Store the global ID's of the points in such a way that they can + be sent to the rank that actually stores the coordinates.. ---*/ + vector > pointBuf(size, vector(0)); + + for(unsigned long i=0; i sendToRank(size, 0); + vector startingIndRanksInPoint(size+1); + startingIndRanksInPoint[0] = 0; + + for(int i=0; i sizeRecv(size, 1); + SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), + MPI_INT, MPI_SUM, SU2_MPI::GetComm()); + + /*--- Send out the messages with the global point numbers. Use nonblocking + sends to avoid deadlock. ---*/ + vector sendReqs(nRankSend); + nRankSend = 0; + for(int i=0; i returnReqs(nRankRecv); + vector > coorReturnBuf(nRankRecv, vector(0)); + + /*--- Get the first index of the points as well as the number of points + currently stored on this rank. ---*/ + const unsigned long firstIndex = pointPartitioner.GetFirstIndexOnRank(rank); + const unsigned long nPointsRead = pointPartitioner.GetSizeOnRank(rank); + + /*--- Loop over the number of ranks from which this rank receives global + point numbers that should be stored on this rank. ---*/ + for(int i=0; i pointRecvBuf(sizeMess); + coorReturnBuf[i].resize(dimension*sizeMess); + + /* Receive the message using a blocking receive. */ + SU2_MPI::Recv(pointRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, + source, rank, SU2_MPI::GetComm(), &status); + + /*--- Loop over the nodes just received and fill the return communication + buffer with the coordinates of the requested nodes. ---*/ + for(int j=0; j= static_cast(nPointsRead)) + SU2_MPI::Error("Invalid point requested. This should not happen.", CURRENT_FUNCTION); + + for(int k=0; k coorRecvBuf(dimension*pointBuf[source].size()); + + /* Receive the message using a blocking receive. */ + SU2_MPI::Recv(coorRecvBuf.data(), coorRecvBuf.size(), MPI_DOUBLE, + source, rank+1, SU2_MPI::GetComm(), &status); + + /*--- Loop over the points just received. ---*/ + for(unsigned long j=0; j &localFaces) { + + /*--- Loop over the locally stored volume elements. ---*/ + unsigned long ind = 0; + for(unsigned long k=0; k::iterator lastFace; + lastFace = unique(localFaces.begin(), localFaces.end()); + localFaces.erase(lastFace, localFaces.end()); +} + +void CMeshReaderBase::GetCornerPointsAllFaces(const unsigned long *elemInfo, + unsigned short &numFaces, + unsigned short nPointsPerFace[], + unsigned long faceConn[6][4]) { + + /*--- Retrieve the element type, polynomial degree of the grid and + number of DOFs for this element and set the pointer for the + connectivity information. ---*/ + const unsigned short VTK_Type = (const unsigned short) elemInfo[0]; + const unsigned short nPolyGrid = (const unsigned short) elemInfo[1]; + const unsigned short nDOFsGrid = (const unsigned short) elemInfo[3]; + const unsigned long *conn = elemInfo + 5; + + /*--- Call the static function GetLocalCornerPointsAllFaces of CPrimalGridFEM + to determine the local numbering of the corner points of the faces. ---*/ + CPrimalGridFEM::GetLocalCornerPointsAllFaces(VTK_Type, nPolyGrid, nDOFsGrid, + numFaces, nPointsPerFace, faceConn); + + /*--- Convert the local values of faceConn to global values. ---*/ + for(unsigned short i=0; i Date: Mon, 3 Feb 2025 11:18:22 +0100 Subject: [PATCH 06/15] The reading of SU2 ASCII files for the FEM solver done via the meshreader classes --- Common/include/geometry/CPhysicalGeometry.hpp | 11 - .../meshreader/CCGNSMeshReaderFEM.hpp | 5 - .../meshreader/CCGNSMeshReaderFVM.hpp | 5 - .../meshreader/CSU2ASCIIMeshReaderBase.hpp | 6 +- .../meshreader/CSU2ASCIIMeshReaderFEM.hpp | 64 +++ .../src/fem/geometry_structure_fem_part.cpp | 439 ------------------ Common/src/geometry/CPhysicalGeometry.cpp | 4 +- .../meshreader/CCGNSMeshReaderFEM.cpp | 4 +- .../meshreader/CCGNSMeshReaderFVM.cpp | 2 - .../meshreader/CSU2ASCIIMeshReaderFEM.cpp | 379 +++++++++++++++ Common/src/geometry/meshreader/meson.build | 1 + 11 files changed, 451 insertions(+), 469 deletions(-) create mode 100644 Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp create mode 100644 Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index b20b2991566..20dba58e52e 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -288,17 +288,6 @@ class CPhysicalGeometry final : public CGeometry { void Read_Mesh(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone); - /*! - * \brief Reads for the FEM solver the geometry of the grid and adjust the boundary - * conditions with the configuration file in parallel (for parmetis). - * \param[in] config - Definition of the particular problem. - * \param[in] val_mesh_filename - Name of the file with the grid information. - * \param[in] val_iZone - Domain to be read from the grid file. - * \param[in] val_nZone - Total number of domains in the grid file. - */ - void Read_SU2_Format_Parallel_FEM(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, - unsigned short val_nZone); - /*! * \brief Routine to load the CGNS grid points from a single zone into the proper SU2 data structures. * \param[in] config - definition of the particular problem. diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp index dfd8aa7c680..8a23b248d89 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp @@ -92,9 +92,4 @@ class CCGNSMeshReaderFEM final : public CCGNSMeshReaderBase { CCGNSMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); - - /*! - * \brief Destructor of the CCGNSMeshReaderFEM class. - */ - ~CCGNSMeshReaderFEM(void); }; diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp index 8e7770c973a..9e22b191fad 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp @@ -92,9 +92,4 @@ class CCGNSMeshReaderFVM final : public CCGNSMeshReaderBase { * \brief Constructor of the CCGNSMeshReaderFVM class. */ CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); - - /*! - * \brief Destructor of the CCGNSMeshReaderFVM class. - */ - ~CCGNSMeshReaderFVM(void); }; diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp index 891141cf9ad..66ecbf97095 100644 --- a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp @@ -86,17 +86,17 @@ class CSU2ASCIIMeshReaderBase : public CMeshReaderBase { /*! * \brief Reads the grid points from an SU2 zone into linear partitions across all ranks. */ - void ReadPointCoordinates(const bool single_pass = false); + virtual void ReadPointCoordinates(const bool single_pass = false); /*! * \brief Reads the interior volume elements from one section of an SU2 zone into linear partitions across all ranks. */ - void ReadVolumeElementConnectivity(const bool single_pass = false); + virtual void ReadVolumeElementConnectivity(const bool single_pass = false); /*! * \brief Reads the surface (boundary) elements from the SU2 zone. */ - void ReadSurfaceElementConnectivity(const bool single_pass = false); + virtual void ReadSurfaceElementConnectivity(const bool single_pass = false); /*! * \brief Helper function to find the current zone in an SU2 ASCII mesh object. diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp new file mode 100644 index 00000000000..6bf11a92dec --- /dev/null +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp @@ -0,0 +1,64 @@ +/*! + * \file CSU2ASCIIMeshReaderFEM.hpp + * \brief Header file for the class CSU2ASCIIMeshReaderFEM. + * The implementations are in the CSU2ASCIIMeshReaderFEM.cpp file. + * \author T. Economon, E. van der Weide + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#include + +#include "CSU2ASCIIMeshReaderBase.hpp" + +/*! + * \class CSU2ASCIIMeshReaderFEM + * \brief Reads a native SU2 ASCII grid into linear partitions for the finite element solver (FEM). + * \author T. Economon, E. van der Weide + */ +class CSU2ASCIIMeshReaderFEM : public CSU2ASCIIMeshReaderBase { + private: + /*! + * \brief Reads the grid points from an SU2 zone into linear partitions across all ranks. + */ + void ReadPointCoordinates(); + + /*! + * \brief Reads the interior volume elements from one section of an SU2 zone into linear partitions across all ranks. + */ + void ReadVolumeElementConnectivity(); + + /*! + * \brief Reads the surface (boundary) elements from one section of an SU2 zone into linear partitions across all ranks. + */ + void ReadSurfaceElementConnectivity(); + + public: + /*! + * \brief Constructor of the CSU2ASCIIMeshReaderFEM class. + */ + CSU2ASCIIMeshReaderFEM(CConfig *val_config, + unsigned short val_iZone, + unsigned short val_nZone); +}; diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index 0af57647bac..c3a3547bf1d 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -360,445 +360,6 @@ void CMatchingFace::Copy(const CMatchingFace& other) { tolForMatching = other.tolForMatching; } -void CPhysicalGeometry::Read_SU2_Format_Parallel_FEM(CConfig* config, const string& val_mesh_filename, - unsigned short val_iZone, unsigned short val_nZone) { - string text_line, Marker_Tag; - ifstream mesh_file; - string::size_type position; - unsigned long nDOFsGrid_Local = 0, loc_element_count = 0; - bool domain_flag = false; - bool time_spectral = config->GetTime_Marching() == TIME_MARCHING::HARMONIC_BALANCE; - unsigned short nMarker_Max = config->GetnMarker_Max(); - nZone = val_nZone; - - /*--- Initialize counters for local/global points & elements ---*/ - Global_nPoint = 0; - Global_nPointDomain = 0; - Global_nElem = 0; - nelem_edge = 0; - Global_nelem_edge = 0; - nelem_triangle = 0; - Global_nelem_triangle = 0; - nelem_quad = 0; - Global_nelem_quad = 0; - nelem_tetra = 0; - Global_nelem_tetra = 0; - nelem_hexa = 0; - Global_nelem_hexa = 0; - nelem_prism = 0; - Global_nelem_prism = 0; - nelem_pyramid = 0; - Global_nelem_pyramid = 0; - - /*--- Allocate memory for the linear partition of the elements of the mesh. - These arrays are the size of the number of ranks. ---*/ - - beg_node = new unsigned long[size]; - end_node = new unsigned long[size]; - nPointLinear = new unsigned long[size]; - - /*--- Open grid file ---*/ - - mesh_file.open(val_mesh_filename.c_str(), ios::in); - - /*--- Check the grid ---*/ - - if (mesh_file.fail()) - SU2_MPI::Error(string("There is no mesh file (CPhysicalGeometry)!! ") + val_mesh_filename, CURRENT_FUNCTION); - - /*--- If more than one, find the zone in the mesh file ---*/ - - if (val_nZone > 1 || time_spectral) { - if (time_spectral) { - if (rank == MASTER_NODE) cout << "Reading time spectral instance " << val_iZone + 1 << ":" << endl; - } else { - while (getline(mesh_file, text_line)) { - /*--- Search for the current domain ---*/ - position = text_line.find("IZONE=", 0); - if (position != string::npos) { - text_line.erase(0, 6); - unsigned short jDomain = atoi(text_line.c_str()); - if (jDomain == val_iZone + 1) { - if (rank == MASTER_NODE) cout << "Reading zone " << val_iZone + 1 << " points:" << endl; - break; - } - } - } - } - } - - /*--- Read grid file with format SU2 ---*/ - - while (getline(mesh_file, text_line)) { - /*--- Read the dimension of the problem ---*/ - - position = text_line.find("NDIME=", 0); - if (position != string::npos) { - if (!domain_flag) { - text_line.erase(0, 6); - nDim = atoi(text_line.c_str()); - if (rank == MASTER_NODE) { - if (nDim == 2) cout << "Two dimensional problem." << endl; - if (nDim == 3) cout << "Three dimensional problem." << endl; - } - domain_flag = true; - } else { - break; - } - } - - /*--- Read the information about inner elements ---*/ - - position = text_line.find("NELEM=", 0); - if (position != string::npos) { - text_line.erase(0, 6); - stringstream stream_line(text_line); - stream_line >> Global_nElem; - - if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) - cout << Global_nElem << " interior elements before parallel partitioning." << endl; - - /*--- Check if the number of cores used is larger than the number of - elements. Terminate if this is the case, because it does not make - sense to do this. ---*/ - unsigned long nCores = size; // Correct for the number of cores per rank. - if (nCores > Global_nElem) { - ostringstream message; - message << "The number of cores, " << nCores; - message << ", is larger than the number of elements, " << Global_nElem << "." << endl; - message << "This is not an efficient use of the resources and therefore " - << "SU2 will terminate."; - - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - /*--- Compute the number of elements that will be on each processor. - This is a linear partitioning with the addition of a simple load - balancing for any remainder elements. ---*/ - unsigned long total_elem_accounted = 0; - for (unsigned long i = 0; i < (unsigned long)size; i++) { - nPointLinear[i] = Global_nElem / size; - total_elem_accounted = total_elem_accounted + nPointLinear[i]; - } - - /*--- Get the number of remainder elements after the even division ---*/ - unsigned long rem_elem = Global_nElem - total_elem_accounted; - for (unsigned long i = 0; i < rem_elem; i++) { - ++nPointLinear[i]; - } - - /*--- Store the local number of elements and the beginning/end index ---*/ - nElem = nPointLinear[rank]; - beg_node[0] = 0; - end_node[0] = beg_node[0] + nPointLinear[0]; - for (unsigned long i = 1; i < (unsigned long)size; i++) { - beg_node[i] = end_node[i - 1]; - end_node[i] = beg_node[i] + nPointLinear[i]; - } - - /*--- Allocate space for elements ---*/ - elem = new CPrimalGrid*[nElem](); - - /*--- Loop over all the elements and store the elements to be stored on - this rank. Furthermore, determine the total amount of DOFs for - the solution (which may differ from the number of DOFS for the - grid). ---*/ - unsigned long nDOFs_tot = 0; - for (unsigned long i = 0; i < Global_nElem; i++) { - getline(mesh_file, text_line); - istringstream elem_line(text_line); - - /*--- Read the value that defines the element type, the polynomial - degree of the geometry and the polynomial degree of the - solution. Extract this info as well. ---*/ - unsigned long typeRead; - elem_line >> typeRead; - unsigned long typeReadErrorMessage = typeRead; - unsigned short nPolySol, nPolyGrid; - if (typeRead > 10000) { - nPolySol = typeRead / 10000 - 1; - typeRead = typeRead % 10000; - nPolyGrid = typeRead / 100 + 1; - } else { - nPolyGrid = typeRead / 100 + 1; - nPolySol = nPolyGrid; - } - - unsigned short VTK_Type = typeRead % 100; - - unsigned short nDOFsGrid = CFEMStandardElementBase::GetNDOFsStatic(VTK_Type, nPolyGrid, typeReadErrorMessage); - unsigned short nDOFsSol = CFEMStandardElementBase::GetNDOFsStatic(VTK_Type, nPolySol, typeReadErrorMessage); - - /*--- Allocate the memory for a new primary grid FEM element if - this element must be stored on this rank. ---*/ - if ((i >= beg_node[rank]) && (i < end_node[rank])) { - elem[loc_element_count] = - new CPrimalGridFEM(i, VTK_Type, nPolyGrid, nPolySol, nDOFsGrid, nDOFsSol, nDOFs_tot, elem_line); - nDOFsGrid_Local += nDOFsGrid; - loc_element_count++; - } - - /*--- Update the total value of the number of DOFs. ---*/ - nDOFs_tot += nDOFsSol; - } - - /*--- Break from the loop to find the element information. ---*/ - break; - } - } - - mesh_file.close(); - - /*--- Create a vector, which contains the global node IDs of the local elements. ---*/ - vector nodeIDsElemLoc; - nodeIDsElemLoc.reserve(nDOFsGrid_Local); - for (unsigned long i = 0; i < loc_element_count; i++) { - unsigned short nDOFsElem = elem[i]->GetnNodes(); - for (unsigned short j = 0; j < nDOFsElem; ++j) nodeIDsElemLoc.push_back(elem[i]->GetNode(j)); - } - - sort(nodeIDsElemLoc.begin(), nodeIDsElemLoc.end()); - vector::iterator lastNode; - lastNode = unique(nodeIDsElemLoc.begin(), nodeIDsElemLoc.end()); - nodeIDsElemLoc.erase(lastNode, nodeIDsElemLoc.end()); - - /*--- Allocate the memory for the coordinates to be stored on this rank. ---*/ - nPoint = nodeIDsElemLoc.size(); - nodes = new CPoint(nPoint, nDim); - - /*--- Open the grid file again and go to the position where - the correct zone is stored. ---*/ - mesh_file.open(val_mesh_filename.c_str(), ios::in); - - if (val_nZone > 1 && !time_spectral) { - while (getline(mesh_file, text_line)) { - position = text_line.find("IZONE=", 0); - if (position != string::npos) { - text_line.erase(0, 6); - unsigned short jDomain = atoi(text_line.c_str()); - if (jDomain == val_iZone + 1) break; - } - } - } - - /*--- While loop to read the point information. ---*/ - while (getline(mesh_file, text_line)) { - position = text_line.find("NPOIN=", 0); - if (position != string::npos) { - text_line.erase(0, 6); - stringstream stream_line(text_line); - stream_line >> Global_nPoint; - - /*--- Loop over the global number of points and store the - ones that are needed on this processor. ---*/ - unsigned long ii = 0; - for (unsigned long i = 0; i < Global_nPoint; ++i) { - getline(mesh_file, text_line); - - if (binary_search(nodeIDsElemLoc.begin(), nodeIDsElemLoc.end(), i)) { - istringstream point_line(text_line); - su2double Coord[3] = {0.0}; - point_line >> Coord[0]; - point_line >> Coord[1]; - if (nDim == 3) point_line >> Coord[2]; - nodes->SetCoord(ii, Coord); - nodes->SetGlobalIndex(ii, i); - ++ii; - } - } - - break; - } - } - - mesh_file.close(); - - /*--- Determine the faces of the local elements. --- */ - vector localFaces; - for (unsigned long k = 0; k < loc_element_count; k++) { - /*--- Get the global IDs of the corner points of all the faces of this elements. ---*/ - unsigned short nFaces; - unsigned short nPointsPerFace[6]; - unsigned long faceConn[6][4]; - - elem[k]->GetCornerPointsAllFaces(nFaces, nPointsPerFace, faceConn); - - /*--- Loop over the faces and add them to localFaces. ---*/ - for (unsigned short i = 0; i < nFaces; ++i) { - CFaceOfElement thisFace; - thisFace.nCornerPoints = nPointsPerFace[i]; - for (unsigned short j = 0; j < nPointsPerFace[i]; ++j) thisFace.cornerPoints[j] = faceConn[i][j]; - thisFace.elemID0 = k + beg_node[rank]; - - thisFace.CreateUniqueNumbering(); - localFaces.push_back(thisFace); - } - } - - /*--- Sort localFaces in increasing order and remove the double entities, - such that the binary search later on is a bit more efficient. ---*/ - sort(localFaces.begin(), localFaces.end()); - vector::iterator lastFace; - lastFace = unique(localFaces.begin(), localFaces.end()); - localFaces.erase(lastFace, localFaces.end()); - - /*--- Open the grid file again and go to the position where - the correct zone is stored. ---*/ - mesh_file.open(val_mesh_filename.c_str(), ios::in); - - if (val_nZone > 1 && !time_spectral) { - while (getline(mesh_file, text_line)) { - position = text_line.find("IZONE=", 0); - if (position != string::npos) { - text_line.erase(0, 6); - unsigned short jDomain = atoi(text_line.c_str()); - if (jDomain == val_iZone + 1) break; - } - } - } - - /*--- While loop to read the boundary information. ---*/ - while (getline(mesh_file, text_line)) { - /*--- Read number of markers ---*/ - position = text_line.find("NMARK=", 0); - if (position != string::npos) { - text_line.erase(0, 6); - istringstream stream_line(text_line); - stream_line >> nMarker; - - if (rank == MASTER_NODE) cout << nMarker << " surface markers." << endl; - config->SetnMarker_All(nMarker); - bound = new CPrimalGrid**[nMarker]; - nElem_Bound = new unsigned long[nMarker]; - Tag_to_Marker = new string[nMarker_Max]; - - for (unsigned short iMarker = 0; iMarker < nMarker; iMarker++) { - getline(mesh_file, text_line); - text_line.erase(0, 11); - text_line.erase(remove(text_line.begin(), text_line.end(), ' '), text_line.end()); - text_line.erase(remove(text_line.begin(), text_line.end(), '\r'), text_line.end()); - text_line.erase(remove(text_line.begin(), text_line.end(), '\n'), text_line.end()); - - Marker_Tag = text_line; - - /*--- Read the number of elements for this marker. ---*/ - getline(mesh_file, text_line); - text_line.erase(0, 13); - istringstream nmark_line(text_line); - unsigned long nElem_Bound_Global; - nmark_line >> nElem_Bound_Global; - if (rank == MASTER_NODE) - cout << nElem_Bound_Global << " boundary elements in index " << iMarker << " (Marker = " << Marker_Tag << ")." - << endl; - - /*--- Define a vector of FEM boundary elements to store the local boundary faces. ---*/ - vector boundElems; - - /*--- Loop over the global boundary faces. ---*/ - for (unsigned long i = 0; i < nElem_Bound_Global; ++i) { - getline(mesh_file, text_line); - istringstream bound_line(text_line); - - /*--- Determine the element type, its number of DOFs and read - its node IDs. ---*/ - unsigned long typeRead; - bound_line >> typeRead; - unsigned short nPolyGrid = typeRead / 100 + 1; - unsigned short VTK_Type = typeRead % 100; - unsigned short nDOFEdgeGrid = nPolyGrid + 1; - - unsigned short nDOFsGrid = 0; - CFaceOfElement thisFace; - thisFace.cornerPoints[0] = 0; - thisFace.cornerPoints[1] = nPolyGrid; - switch (VTK_Type) { - case LINE: - nDOFsGrid = nDOFEdgeGrid; - thisFace.nCornerPoints = 2; - break; - - case TRIANGLE: - nDOFsGrid = nDOFEdgeGrid * (nDOFEdgeGrid + 1) / 2; - thisFace.nCornerPoints = 3; - thisFace.cornerPoints[2] = nDOFsGrid - 1; - break; - - case QUADRILATERAL: - nDOFsGrid = nDOFEdgeGrid * nDOFEdgeGrid; - thisFace.nCornerPoints = 4; - thisFace.cornerPoints[2] = nPolyGrid * nDOFEdgeGrid; - thisFace.cornerPoints[3] = nDOFsGrid - 1; - break; - - default: - ostringstream message; - message << "Unknown FEM boundary element value, " << typeRead << ", in " << val_mesh_filename; - SU2_MPI::Error(message.str(), CURRENT_FUNCTION); - } - - vector nodeIDs(nDOFsGrid); - for (unsigned short j = 0; j < nDOFsGrid; ++j) bound_line >> nodeIDs[j]; - - /*--- Convert the local numbering of thisFace to global numbering - and create a unique numbering of these nodes. ---*/ - for (unsigned short j = 0; j < thisFace.nCornerPoints; ++j) - thisFace.cornerPoints[j] = nodeIDs[thisFace.cornerPoints[j]]; - thisFace.CreateUniqueNumbering(); - - /*--- Check if this boundary face must be stored on this rank. - If so, create an object of CBoundaryFace and add it - to boundElems. ---*/ - vector::iterator low; - low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); - if (low != localFaces.end()) { - if (!(thisFace < *low)) { - CBoundaryFace thisBoundFace; - thisBoundFace.VTK_Type = VTK_Type; - thisBoundFace.nPolyGrid = nPolyGrid; - thisBoundFace.nDOFsGrid = nDOFsGrid; - thisBoundFace.globalBoundElemID = i; - thisBoundFace.domainElementID = low->elemID0; - thisBoundFace.Nodes = nodeIDs; - - boundElems.push_back(thisBoundFace); - } - } - } - - /*--- Allocate space for the boundary elements and store the ones - whose parent element is stored on this rank. ---*/ - nElem_Bound[iMarker] = boundElems.size(); - bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]]; - - for (unsigned long i = 0; i < nElem_Bound[iMarker]; ++i) - bound[iMarker][i] = new CPrimalGridBoundFEM(boundElems[i].globalBoundElemID, boundElems[i].domainElementID, - boundElems[i].VTK_Type, boundElems[i].nPolyGrid, - boundElems[i].nDOFsGrid, boundElems[i].Nodes); - - /*--- Update config information storing the boundary information in the right place ---*/ - Tag_to_Marker[config->GetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; - config->SetMarker_All_TagBound(iMarker, Marker_Tag); - config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); - config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); - config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); - config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); - config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); - config->SetMarker_All_Analyze(iMarker, config->GetMarker_CfgFile_Analyze(Marker_Tag)); - config->SetMarker_All_ZoneInterface(iMarker, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag)); - config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); - config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); - config->SetMarker_All_SobolevBC(iMarker, config->GetMarker_CfgFile_SobolevBC(Marker_Tag)); - config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); - config->SetMarker_All_SendRecv(iMarker, NONE); - } - - break; - } - } - - mesh_file.close(); -} - void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Initialize the color vector of the elements. ---*/ for (unsigned long i = 0; i < nElem; ++i) elem[i]->SetColor(0); diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 6f7f4a0fe98..b53f2ba62c6 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -31,6 +31,7 @@ #include "../../include/toolboxes/CLinearPartitioner.hpp" #include "../../include/toolboxes/C1DInterpolation.hpp" #include "../../include/toolboxes/geometry_toolbox.hpp" +#include "../../include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp" #include "../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" #include "../../include/geometry/meshreader/CCGNSMeshReaderFVM.hpp" #include "../../include/geometry/meshreader/CCGNSMeshReaderFEM.hpp" @@ -3449,7 +3450,8 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena CMeshReaderBase* Mesh = nullptr; switch (val_format) { case SU2: - Mesh = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) Mesh = new CSU2ASCIIMeshReaderFEM(config, val_iZone, val_nZone); + else Mesh = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); break; case CGNS_GRID: if (fem_solver) Mesh = new CCGNSMeshReaderFEM(config, val_iZone, val_nZone); diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp index 9f527b4e6cc..f6c48c62f05 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -61,8 +61,6 @@ CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(CConfig* val_config, unsigned short val_i #endif } -CCGNSMeshReaderFEM::~CCGNSMeshReaderFEM() = default; - #ifdef HAVE_CGNS void CCGNSMeshReaderFEM::ReadCGNSConnectivityRangeSection(const int val_section, const unsigned long val_firstIndex, @@ -547,4 +545,4 @@ void CCGNSMeshReaderFEM::CommPointCoordinates(void) { SU2_MPI::Barrier(SU2_MPI::GetComm()); #endif -} \ No newline at end of file +} diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp index 147f5de0323..6e3bfb15189 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp @@ -71,8 +71,6 @@ CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_i #endif } -CCGNSMeshReaderFVM::~CCGNSMeshReaderFVM() = default; - #ifdef HAVE_CGNS void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { /*--- In this routine, each rank will read a chunk of the element diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp new file mode 100644 index 00000000000..277c7a983f8 --- /dev/null +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp @@ -0,0 +1,379 @@ +/*! + * \file CSU2ASCIIMeshReaderFEM.cpp + * \brief Reads a native SU2 ASCII grid into linear partitions for the + * finite element solver (FEM). + * \author T. Economon, E. van der Weide + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#include "../../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp" +#include "../../../include/fem/fem_standard_element.hpp" + +CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone) + : CSU2ASCIIMeshReaderBase(val_config, val_iZone, val_nZone) { + + /* Read the basic metadata and perform some basic error checks. */ + ReadMetadata(true, val_config); + + /*--- Read the volume connectivity and distribute it + linearly over the MPI ranks. ---*/ + ReadVolumeElementConnectivity(); + + /*--- Read the coordinates of the points that are needed + on this MPI rank. ---*/ + ReadPointCoordinates(); + + /*--- Read the surface connectivity and store the surface elements whose + corresponding volume element is stored on this MPI rank. ---*/ + ReadSurfaceElementConnectivity(); +} + +void CSU2ASCIIMeshReaderFEM::ReadPointCoordinates() { + + /*--- Loop over the local elements to determine the global + point IDs to be stored on this rank. --*/ + unsigned long ind = 0; + for(unsigned long i=0; i::iterator lastNode; + lastNode = unique(globalPointIDs.begin(), globalPointIDs.end()); + globalPointIDs.erase(lastNode, globalPointIDs.end()); + + /*--- Determine the number of locally stored points. ---*/ + numberOfLocalPoints = globalPointIDs.size(); + + /*--- Prepare our data structure for the point coordinates. ---*/ + localPointCoordinates.resize(dimension); + for(int k=0; k> nodeID; + localVolumeElementConnectivity.push_back(nodeID); + } + + /*--- If a linear element is used, the node numbering for non-simplices + must be adapted. The reason is that compatability with the original + SU2 format is maintained for linear elements, but for the FEM solver + the nodes of the elements are stored row-wise. ---*/ + if(nPolyGrid == 1) { + switch( VTK_Type ) { + + case QUADRILATERAL: + swap(localVolumeElementConnectivity[ind+2], + localVolumeElementConnectivity[ind+3]); + break; + + case HEXAHEDRON: + swap(localVolumeElementConnectivity[ind+2], + localVolumeElementConnectivity[ind+3]); + swap(localVolumeElementConnectivity[ind+6], + localVolumeElementConnectivity[ind+7]); + break; + + case PYRAMID: + swap(localVolumeElementConnectivity[ind+2], + localVolumeElementConnectivity[ind+3]); + break; + } + } + } + + /*--- Close the mesh file again. ---*/ + mesh_file.close(); +} + +void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { + + /*--- Determine the vector to hold the faces of the local elements. ---*/ + vector localFaces; + DetermineFacesVolumeElements(localFaces); + + /*--- We already read in the number of markers with the metadata. + Allocate the memory for the marker names, number of local surface + elements and the first index of the surface element connectivity. ---*/ + surfaceElementConnectivity.resize(numberOfMarkers); + markerNames.resize(numberOfMarkers); + numberOfLocalSurfaceElements.resize(numberOfMarkers, 0); + + /*--- Open the mesh file and jump to our zone. ---*/ + mesh_file.open(meshFilename, ios::in); + FastForwardToMyZone(); + + /*--- Find the section containing the markers. ---*/ + string text_line; + while (getline (mesh_file, text_line)) { + string::size_type position = text_line.find ("NMARK=",0); + if (position != string::npos) break; + } + + /*--- Loop over the number of boundary markers. ---*/ + for(unsigned long iMarker=0; iMarker connFace(nDOFsGrid); + for(unsigned short j=0; j> connFace[j]; + + /*--- If a linear quadrilateral is used, the node numbering must be adapted. + The reason is that compatability with the original SU2 format is + maintained for linear elements, but for the FEM solver the nodes + of the elements are stored row-wise. ---*/ + if((nPolyGrid == 1) && (VTK_Type == QUADRILATERAL)) + swap(connFace[2], connFace[3]); + + /*--- Convert the local numbering of thisFace to global numbering + and create a unique numbering of corner points. ---*/ + for(unsigned short j=0; j::iterator low; + low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); + if(low != localFaces.end()) { + if( !(thisFace < *low) ) { + + /*--- Update the counter for this boundary marker and store + the meta data in surfaceElementConnectivity. ---*/ + ++numberOfLocalSurfaceElements[iMarker]; + + surfaceElementConnectivity[iMarker].push_back(VTK_Type); + surfaceElementConnectivity[iMarker].push_back(nPolyGrid); + surfaceElementConnectivity[iMarker].push_back(nDOFsGrid); + surfaceElementConnectivity[iMarker].push_back(i); // Global surface elem ID. + surfaceElementConnectivity[iMarker].push_back(low->elemID0); // Global volume elem ID. + + /*--- Copy the connectivity to surfaceElementConnectivity. ---*/ + surfaceElementConnectivity[iMarker].insert(surfaceElementConnectivity[iMarker].end(), + connFace.begin(), connFace.end()); + } + } + } + } + + /*--- Close the mesh file again. ---*/ + mesh_file.close(); +} \ No newline at end of file diff --git a/Common/src/geometry/meshreader/meson.build b/Common/src/geometry/meshreader/meson.build index cbc952d7649..6d994fb8420 100644 --- a/Common/src/geometry/meshreader/meson.build +++ b/Common/src/geometry/meshreader/meson.build @@ -6,4 +6,5 @@ common_src += files(['CBoxMeshReaderFVM.cpp', 'CMeshReaderBase.cpp', 'CRectangularMeshReaderFVM.cpp', 'CSU2ASCIIMeshReaderBase.cpp', + 'CSU2ASCIIMeshReaderFEM.cpp', 'CSU2ASCIIMeshReaderFVM.cpp']) From 00a735b55196217837140aed8cd78ae6022c5f4c Mon Sep 17 00:00:00 2001 From: vdweide Date: Mon, 3 Feb 2025 14:54:40 +0100 Subject: [PATCH 07/15] The reading of Rectangular and Box grids for the FEM solver done via the meshreader classes --- Common/include/CConfig.hpp | 7 + .../geometry/meshreader/CBoxMeshReaderFEM.hpp | 85 ++++ .../geometry/meshreader/CBoxMeshReaderFVM.hpp | 2 +- .../meshreader/CCGNSMeshReaderBase.hpp | 2 +- .../meshreader/CCGNSMeshReaderFEM.hpp | 9 +- .../meshreader/CCGNSMeshReaderFVM.hpp | 7 +- .../meshreader/CRectangularMeshReaderFEM.hpp | 79 ++++ .../meshreader/CRectangularMeshReaderFVM.hpp | 5 + .../meshreader/CSU2ASCIIMeshReaderFEM.hpp | 9 +- .../meshreader/CSU2ASCIIMeshReaderFVM.hpp | 5 + Common/src/CConfig.cpp | 3 + Common/src/geometry/CPhysicalGeometry.cpp | 8 +- .../geometry/meshreader/CBoxMeshReaderFEM.cpp | 369 ++++++++++++++++++ .../geometry/meshreader/CBoxMeshReaderFVM.cpp | 2 +- .../meshreader/CCGNSMeshReaderBase.cpp | 5 +- .../meshreader/CCGNSMeshReaderFEM.cpp | 5 +- .../meshreader/CCGNSMeshReaderFVM.cpp | 5 +- .../meshreader/CRectangularMeshReaderFEM.cpp | 271 +++++++++++++ .../meshreader/CRectangularMeshReaderFVM.cpp | 2 + .../meshreader/CSU2ASCIIMeshReaderBase.cpp | 3 +- .../meshreader/CSU2ASCIIMeshReaderFEM.cpp | 7 +- .../meshreader/CSU2ASCIIMeshReaderFVM.cpp | 5 +- Common/src/geometry/meshreader/meson.build | 4 +- 23 files changed, 878 insertions(+), 21 deletions(-) create mode 100644 Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp create mode 100644 Common/include/geometry/meshreader/CRectangularMeshReaderFEM.hpp create mode 100644 Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp create mode 100644 Common/src/geometry/meshreader/CRectangularMeshReaderFEM.cpp diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 58918bfdc2c..d55416ed681 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -804,6 +804,7 @@ class CConfig { nRefOriginMoment_Z; /*!< \brief Number of Z-coordinate moment computation origins. */ unsigned short nMesh_Box_Size; short *Mesh_Box_Size; /*!< \brief Array containing the number of grid points in the x-, y-, and z-directions for the analytic RECTANGLE and BOX grid formats. */ + unsigned short Mesh_Box_PSolFEM; /*!< \brief FEM polynomial degree of the solution for the RECTANGLE and BOX grid formats. */ string Mesh_FileName, /*!< \brief Mesh input file. */ Mesh_Out_FileName, /*!< \brief Mesh output file. */ Solution_FileName, /*!< \brief Flow solution input file. */ @@ -9606,6 +9607,12 @@ class CConfig { */ su2double GetMeshBoxOffset(unsigned short val_iDim) const { return mesh_box_offset[val_iDim]; } + /*! + * \brief Get the polynomial degree of the FEM solution for the analytic RECTANGLE or BOX. + * \return The polynomial degree of the FEM solution. + */ + unsigned short GetMeshBoxPSolFEM(void) const { return Mesh_Box_PSolFEM; } + /*! * \brief Get the number of screen output variables requested (maximum 6) */ diff --git a/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp new file mode 100644 index 00000000000..acfafef6365 --- /dev/null +++ b/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp @@ -0,0 +1,85 @@ +/*! + * \file CBoxMeshReaderFEM.hpp + * \brief Header file for the class CBoxMeshReaderFEM. + * The implementations are in the CBoxMeshReaderFEM.cpp file. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#include "CMeshReaderBase.hpp" + +/*! + * \class CBoxMeshReaderFEM + * \brief Reads a 3D box grid into linear partitions for the finite element solver (FEM). + * \author: T. Economon, E. van der Weide + */ +class CBoxMeshReaderFEM final: public CMeshReaderBase { + +private: + + unsigned long nNode; /*!< \brief Number of grid nodes in the x-direction. */ + unsigned long mNode; /*!< \brief Number of grid nodes in the y-direction. */ + unsigned long pNode; /*!< \brief Number of grid nodes in the z-direction. */ + + su2double Lx; /*!< \brief Length of the domain in the x-direction. */ + su2double Ly; /*!< \brief Length of the domain in the y-direction. */ + su2double Lz; /*!< \brief Length of the domain in the z-direction. */ + + su2double Ox; /*!< \brief Offset of the domain from 0.0 in the x-direction. */ + su2double Oy; /*!< \brief Offset of the domain from 0.0 in the y-direction. */ + su2double Oz; /*!< \brief Offset of the domain from 0.0 in the z-direction. */ + + unsigned short KindElem; /*!< \brief VTK identifier of the interior elements. */ + unsigned short KindBound; /*!< \brief VTK identifier of the surface elements. */ + + unsigned short nPolySol; /*!< \brief Polynomial degree of the solution. */ + + /*! + * \brief Computes and stores the grid points based on an analytic definition of a box grid. + */ + void ComputeBoxPointCoordinates(); + + /*! + * \brief Computes and stores the volume element connectivity based on an analytic definition of a box grid. + */ + void ComputeBoxVolumeConnectivity(); + + /*! + * \brief Computes and stores the surface element connectivity based on an analytic definition of a box grid. + */ + void ComputeBoxSurfaceConnectivity(); + +public: + + /*! + * \brief Constructor of the CBoxMeshReaderFEM class. + */ + CBoxMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CBoxMeshReaderFEM class. + */ + ~CBoxMeshReaderFEM(void) override; +}; diff --git a/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp index 74956a61bba..a557630e7c8 100644 --- a/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CBoxMeshReaderFVM.hpp @@ -71,7 +71,7 @@ class CBoxMeshReaderFVM : public CMeshReaderBase { /*! * \brief Constructor of the CBoxMeshReaderFVM class. */ - CBoxMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + CBoxMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); /*! * \brief Destructor of the CBoxMeshReaderFVM class. diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp index ef12386e12c..01574423fcc 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderBase.hpp @@ -99,7 +99,7 @@ class CCGNSMeshReaderBase : public CMeshReaderBase { /*! * \brief Constructor of the CCGNSMeshReaderBase class. */ - CCGNSMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + CCGNSMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); /*! * \brief Destructor of the CCGNSMeshReaderBase class. diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp index 8a23b248d89..a07bf969f4c 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp @@ -89,7 +89,10 @@ class CCGNSMeshReaderFEM final : public CCGNSMeshReaderBase { /*! * \brief Constructor of the CCGNSMeshReaderFEM class. */ - CCGNSMeshReaderFEM(CConfig *val_config, - unsigned short val_iZone, - unsigned short val_nZone); + CCGNSMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CCGNSMeshReaderFEM class. + */ + ~CCGNSMeshReaderFEM(void) override; }; diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp index 9e22b191fad..fe8612b3bbb 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFVM.hpp @@ -91,5 +91,10 @@ class CCGNSMeshReaderFVM final : public CCGNSMeshReaderBase { /*! * \brief Constructor of the CCGNSMeshReaderFVM class. */ - CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + CCGNSMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CCGNSMeshReaderFVM class. + */ + ~CCGNSMeshReaderFVM(void) override; }; diff --git a/Common/include/geometry/meshreader/CRectangularMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CRectangularMeshReaderFEM.hpp new file mode 100644 index 00000000000..cc4745659a9 --- /dev/null +++ b/Common/include/geometry/meshreader/CRectangularMeshReaderFEM.hpp @@ -0,0 +1,79 @@ +/*! + * \file CRectangularMeshReaderFEM.hpp + * \brief Header file for the class CRectangularMeshReaderFEM. + * The implementations are in the CRectangularMeshReaderFEM.cpp file. + * \author T. Economon + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#pragma once + +#include "CMeshReaderBase.hpp" + +/*! + * \class CRectangularMeshReaderFEM + * \brief Reads a 2D rectangular grid into linear partitions for the finite element solver (FEM). + * \author: T. Economon, E. van der Weide + */ +class CRectangularMeshReaderFEM : public CMeshReaderBase { + private: + unsigned long nNode; /*!< \brief Number of grid nodes in the x-direction. */ + unsigned long mNode; /*!< \brief Number of grid nodes in the y-direction. */ + + su2double Lx; /*!< \brief Length of the domain in the x-direction. */ + su2double Ly; /*!< \brief Length of the domain in the y-direction. */ + + su2double Ox; /*!< \brief Offset of the domain from 0.0 in the x-direction. */ + su2double Oy; /*!< \brief Offset of the domain from 0.0 in the y-direction. */ + + unsigned short KindElem; /*!< \brief VTK identifier of the interior elements. */ + unsigned short KindBound; /*!< \brief VTK identifier of the surface elements. */ + + unsigned short nPolySol; /*!< \brief Polynomial degree of the solution. */ + + /*! + * \brief Computes and stores the grid points based on an analytic definition of a rectangular grid. + */ + void ComputeRectangularPointCoordinates(); + + /*! + * \brief Computes and stores the volume element connectivity based on an analytic definition of a rectangular grid. + */ + void ComputeRectangularVolumeConnectivity(); + + /*! + * \brief Computes and stores the surface element connectivity based on an analytic definition of a rectangular grid. + */ + void ComputeRectangularSurfaceConnectivity(); + + public: + /*! + * \brief Constructor of the CRectangularMeshReaderFEM class. + */ + CRectangularMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CRectangularMeshReaderFEM class. + */ + ~CRectangularMeshReaderFEM(void) override; +}; diff --git a/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp index acdc94b8a43..30f28354d12 100644 --- a/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CRectangularMeshReaderFVM.hpp @@ -69,4 +69,9 @@ class CRectangularMeshReaderFVM : public CMeshReaderBase { * \brief Constructor of the CRectangularMeshReaderFVM class. */ CRectangularMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CRectangularMeshReaderFVM class. + */ + ~CRectangularMeshReaderFVM(void) override; }; diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp index 6bf11a92dec..3b4759a9301 100644 --- a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp @@ -58,7 +58,10 @@ class CSU2ASCIIMeshReaderFEM : public CSU2ASCIIMeshReaderBase { /*! * \brief Constructor of the CSU2ASCIIMeshReaderFEM class. */ - CSU2ASCIIMeshReaderFEM(CConfig *val_config, - unsigned short val_iZone, - unsigned short val_nZone); + CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CSU2ASCIIMeshReaderFEM class. + */ + ~CSU2ASCIIMeshReaderFEM(void) override; }; diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp index 10fada303d2..20f88bc66bc 100644 --- a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp @@ -49,4 +49,9 @@ class CSU2ASCIIMeshReaderFVM : public CSU2ASCIIMeshReaderBase { * \brief Constructor of the CSU2ASCIIMeshReaderFVM class. */ CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \brief Destructor of the CSU2ASCIIMeshReaderFVM class. + */ + ~CSU2ASCIIMeshReaderFVM(void) override; }; diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index cc5bd3faca6..d54d1dc3a6c 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2145,6 +2145,9 @@ void CConfig::SetConfig_Options() { mesh_box_offset[0] = 0.0; mesh_box_offset[1] = 0.0; mesh_box_offset[2] = 0.0; addDoubleArrayOption("MESH_BOX_OFFSET", 3, mesh_box_offset); + /* DESCRIPTION: Polynomial degree of the FEM solution for the RECTANGLE or BOX grid. (default: 1). */ + addUnsignedShortOption("MESH_BOX_POLY_SOL_FEM", Mesh_Box_PSolFEM, 1); + /* DESCRIPTION: Determine if the mesh file supports multizone. \n DEFAULT: true (temporarily) */ addBoolOption("MULTIZONE_MESH", Multizone_Mesh, true); /* DESCRIPTION: Determine if we need to allocate memory to store the multizone residual. \n DEFAULT: false (temporarily) */ diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index b53f2ba62c6..f3cd14e2bd4 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -35,7 +35,9 @@ #include "../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" #include "../../include/geometry/meshreader/CCGNSMeshReaderFVM.hpp" #include "../../include/geometry/meshreader/CCGNSMeshReaderFEM.hpp" +#include "../../include/geometry/meshreader/CRectangularMeshReaderFEM.hpp" #include "../../include/geometry/meshreader/CRectangularMeshReaderFVM.hpp" +#include "../../include/geometry/meshreader/CBoxMeshReaderFEM.hpp" #include "../../include/geometry/meshreader/CBoxMeshReaderFVM.hpp" #include "../../include/geometry/primal_grid/CPrimalGrid.hpp" @@ -3458,10 +3460,12 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena else Mesh = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); break; case RECTANGLE: - Mesh = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) Mesh = new CRectangularMeshReaderFEM(config, val_iZone, val_nZone); + else Mesh = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); break; case BOX: - Mesh = new CBoxMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) Mesh = new CBoxMeshReaderFEM(config, val_iZone, val_nZone); + else Mesh = new CBoxMeshReaderFVM(config, val_iZone, val_nZone); break; default: SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION); diff --git a/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp new file mode 100644 index 00000000000..56551341517 --- /dev/null +++ b/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp @@ -0,0 +1,369 @@ +/*! + * \file CBoxMeshReaderFEM.cpp + * \brief Reads a 3D box grid into linear partitions for the + * finite element solver (FEM). + * \author T. Economon, E. van der Weide + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#include "../../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../../include/geometry/meshreader/CBoxMeshReaderFEM.hpp" + +CBoxMeshReaderFEM::CBoxMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, + unsigned short val_nZone) + : CMeshReaderBase(val_config, val_iZone, val_nZone) { + + /* The box mesh is always 3D. */ + dimension = 3; + + /* Set the VTK type for the interior elements and the boundary elements. */ + KindElem = HEXAHEDRON; + KindBound = QUADRILATERAL; + + /* The number of grid nodes in the i, j and k directions. */ + nNode = config->GetMeshBoxSize(0); + mNode = config->GetMeshBoxSize(1); + pNode = config->GetMeshBoxSize(2); + + /* Lengths for non-square domains. */ + Lx = config->GetMeshBoxLength(0); + Ly = config->GetMeshBoxLength(1); + Lz = config->GetMeshBoxLength(2); + + /* Offsets in x, y and z directions from 0.0. */ + Ox = config->GetMeshBoxOffset(0); + Oy = config->GetMeshBoxOffset(1); + Oz = config->GetMeshBoxOffset(2); + + /* Polynomial degree of the solution. */ + nPolySol = config->GetMeshBoxPSolFEM(); + + /*--- Compute and store the interior elements, points, and surface elements + for this rank, for which simple analytic formulae can be used. ---*/ + ComputeBoxVolumeConnectivity(); + ComputeBoxPointCoordinates(); + ComputeBoxSurfaceConnectivity(); +} + +CBoxMeshReaderFEM::~CBoxMeshReaderFEM() = default; + +void CBoxMeshReaderFEM::ComputeBoxPointCoordinates() { + + /*--- Set the global count of points based on the grid dimensions. ---*/ + numberOfGlobalPoints = nNode*mNode*pNode; + + /*--- Loop over the local elements to determine the global + point IDs to be stored on this rank. --*/ + unsigned long ind = 0; + for(unsigned long i=0; i::iterator lastNode; + lastNode = unique(globalPointIDs.begin(), globalPointIDs.end()); + globalPointIDs.erase(lastNode, globalPointIDs.end()); + + /*--- Determine the number of locally stored points. ---*/ + numberOfLocalPoints = globalPointIDs.size(); + + /*--- Allocate the memory for the locally stored points. ---*/ + localPointCoordinates.resize(dimension); + for (int k = 0; k < dimension; k++) + localPointCoordinates[k].resize(numberOfLocalPoints); + + /*--- Loop over the locally stored points. ---*/ + const unsigned long nPointIJ = nNode*mNode; + for(unsigned long i=0; i(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[0].push_back(KindBound); // VTK type. + surfaceElementConnectivity[0].push_back(1); // Poly degree grid. + surfaceElementConnectivity[0].push_back(4); // Number of grid DOFs. + surfaceElementConnectivity[0].push_back(ind); // Global surface element ID. + surfaceElementConnectivity[0].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[0].push_back(kNode*mNode*nNode + jNode*nNode); + surfaceElementConnectivity[0].push_back((kNode+1)*mNode*nNode + jNode*nNode); + surfaceElementConnectivity[0].push_back(kNode*mNode*nNode + (jNode+1)*nNode); + surfaceElementConnectivity[0].push_back((kNode+1)*mNode*nNode + (jNode+1)*nNode); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[0]; + } + } + } + + /*--- Loop over all faces on the xMax (= iMax) boundary. ---*/ + markerNames[1] = "x_plus"; + + ind = 0; + for(unsigned long kNode = 0; kNode < pNode-1; ++kNode) { + for(unsigned long jNode = 0; jNode < mNode-1; ++jNode, ++ind) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = kNode*nElemIJ + jNode*nElemI + nElemI-1; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[1].push_back(KindBound); // VTK type. + surfaceElementConnectivity[1].push_back(1); // Poly degree grid. + surfaceElementConnectivity[1].push_back(4); // Number of grid DOFs. + surfaceElementConnectivity[1].push_back(ind); // Global surface element ID. + surfaceElementConnectivity[1].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[1].push_back(kNode*mNode*nNode + jNode*nNode + (nNode-1)); + surfaceElementConnectivity[1].push_back(kNode*mNode*nNode + (jNode+1)*nNode + (nNode-1)); + surfaceElementConnectivity[1].push_back((kNode+1)*mNode*nNode + jNode*nNode + (nNode-1)); + surfaceElementConnectivity[1].push_back((kNode+1)*mNode*nNode + (jNode+1)*nNode + (nNode-1)); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[1]; + } + } + } + + /*--- Loop over all faces on the yMin (= jMin) boundary. ---*/ + markerNames[2] = "y_minus"; + + ind = 0; + for (unsigned long kNode = 0; kNode < pNode-1; ++kNode) { + for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = kNode*nElemIJ + iNode; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[2].push_back(KindBound); // VTK type. + surfaceElementConnectivity[2].push_back(1); // Poly degree grid. + surfaceElementConnectivity[2].push_back(4); // Number of grid DOFs. + surfaceElementConnectivity[2].push_back(ind); // Global surface element ID. + surfaceElementConnectivity[2].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[2].push_back(kNode*mNode*nNode + iNode); + surfaceElementConnectivity[2].push_back(kNode*mNode*nNode + iNode+1); + surfaceElementConnectivity[2].push_back((kNode+1)*mNode*nNode + iNode); + surfaceElementConnectivity[2].push_back((kNode+1)*mNode*nNode + iNode+1); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[2]; + } + } + } + + /*--- Loop over all faces on the yMax (= jMax) boundary. ---*/ + markerNames[3] = "y_plus"; + + ind = 0; + for (unsigned long kNode = 0; kNode < pNode-1; ++kNode) { + for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = kNode*nElemIJ + (mNode-2)*nElemI + iNode; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[3].push_back(KindBound); // VTK type. + surfaceElementConnectivity[3].push_back(1); // Poly degree grid. + surfaceElementConnectivity[3].push_back(4); // Number of grid DOFs. + surfaceElementConnectivity[3].push_back(ind); // Global surface element ID. + surfaceElementConnectivity[3].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[3].push_back(kNode*mNode*nNode + (mNode-1)*nNode + iNode); + surfaceElementConnectivity[3].push_back(kNode*mNode*nNode + (mNode-1)*nNode + iNode+1); + surfaceElementConnectivity[3].push_back((kNode+1)*mNode*nNode + (mNode-1)*nNode + iNode); + surfaceElementConnectivity[3].push_back((kNode+1)*mNode*nNode + (mNode-1)*nNode + iNode+1); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[3]; + } + } + } + + /*--- Loop over all faces on the zMin (= kMin) boundary. ---*/ + markerNames[4] = "z_minus"; + + ind = 0; + for (unsigned long jNode = 0; jNode < mNode-1; ++jNode) { + for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = jNode*nElemI + iNode; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[4].push_back(KindBound); // VTK type. + surfaceElementConnectivity[4].push_back(1); // Poly degree grid. + surfaceElementConnectivity[4].push_back(4); // Number of grid DOFs. + surfaceElementConnectivity[4].push_back(ind); // Global surface element ID. + surfaceElementConnectivity[4].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[4].push_back(jNode*nNode + iNode); + surfaceElementConnectivity[4].push_back(jNode*nNode + iNode+1); + surfaceElementConnectivity[4].push_back((jNode+1)*nNode + iNode); + surfaceElementConnectivity[4].push_back((jNode+1)*nNode + iNode+1); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[4]; + } + } + } + + /*--- Loop over all faces on the zMax (= kMax) boundary. ---*/ + markerNames[5] = "z_plus"; + + ind = 0; + for (unsigned long jNode = 0; jNode < mNode-1; ++jNode) { + for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = (pNode-2)*nElemIJ + jNode*nElemI + iNode; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[5].push_back(KindBound); // VTK type. + surfaceElementConnectivity[5].push_back(1); // Poly degree grid. + surfaceElementConnectivity[5].push_back(4); // Number of grid DOFs. + surfaceElementConnectivity[5].push_back(ind); // Global surface element ID. + surfaceElementConnectivity[5].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + jNode*nNode + iNode); + surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + jNode*nNode + iNode+1); + surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + (jNode+1)*nNode + iNode); + surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + (jNode+1)*nNode + iNode+1); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[5]; + } + } + } +} diff --git a/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp index 8330f1ea6fe..962e32e478d 100644 --- a/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp @@ -29,7 +29,7 @@ #include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CBoxMeshReaderFVM.hpp" -CBoxMeshReaderFVM::CBoxMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CBoxMeshReaderFVM::CBoxMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : CMeshReaderBase(val_config, val_iZone, val_nZone) { /* The box mesh is always 3D. */ dimension = 3; diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp index 8a0f4e2bdb6..379176ad6c9 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp @@ -29,7 +29,8 @@ #include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CCGNSMeshReaderBase.hpp" -CCGNSMeshReaderBase::CCGNSMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CCGNSMeshReaderBase::CCGNSMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, + unsigned short val_nZone) : CMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS /*--- Leave the option to do something in the future here. ---*/ @@ -407,4 +408,4 @@ string CCGNSMeshReaderBase::GetCGNSElementType(ElementType_t val_elem_type, int& return elem_name; } -#endif \ No newline at end of file +#endif diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp index f6c48c62f05..48c0b267cfb 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -30,7 +30,8 @@ #include "../../../include/geometry/meshreader/CCGNSMeshReaderFEM.hpp" #include "../../../include/geometry/meshreader/CCGNSElementType.hpp" -CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, + unsigned short val_nZone) : CCGNSMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS OpenCGNSFile(config->GetMesh_FileName()); @@ -61,6 +62,8 @@ CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(CConfig* val_config, unsigned short val_i #endif } +CCGNSMeshReaderFEM::~CCGNSMeshReaderFEM() = default; + #ifdef HAVE_CGNS void CCGNSMeshReaderFEM::ReadCGNSConnectivityRangeSection(const int val_section, const unsigned long val_firstIndex, diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp index 6e3bfb15189..61b6cef7020 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp @@ -29,7 +29,8 @@ #include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CCGNSMeshReaderFVM.hpp" -CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(const CConfig* val_config, unsigned short val_iZone, + unsigned short val_nZone) : CCGNSMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS OpenCGNSFile(config->GetMesh_FileName()); @@ -71,6 +72,8 @@ CCGNSMeshReaderFVM::CCGNSMeshReaderFVM(CConfig* val_config, unsigned short val_i #endif } +CCGNSMeshReaderFVM::~CCGNSMeshReaderFVM() = default; + #ifdef HAVE_CGNS void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { /*--- In this routine, each rank will read a chunk of the element diff --git a/Common/src/geometry/meshreader/CRectangularMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CRectangularMeshReaderFEM.cpp new file mode 100644 index 00000000000..ceda417b7d7 --- /dev/null +++ b/Common/src/geometry/meshreader/CRectangularMeshReaderFEM.cpp @@ -0,0 +1,271 @@ +/*! + * \file CRectangularMeshReaderFEM.cpp + * \brief Reads a 2D rectangular grid into linear partitions for the + * finite element solver (FEM). + * \author T. Economon, E. van der Weide + * \version 8.1.0 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 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. + * + * SU2 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 SU2. If not, see . + */ + +#include "../../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../../include/geometry/meshreader/CRectangularMeshReaderFEM.hpp" + +CRectangularMeshReaderFEM::CRectangularMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, + unsigned short val_nZone) +: CMeshReaderBase(val_config, val_iZone, val_nZone) { + + /* The rectangular mesh is always 2D. */ + dimension = 2; + + /* Set the VTK type for the interior elements and the boundary elements. */ + KindElem = QUADRILATERAL; + KindBound = LINE; + + /* The number of nodes in the i and j directions. */ + nNode = config->GetMeshBoxSize(0); + mNode = config->GetMeshBoxSize(1); + + /* Lengths for non-square domains. */ + Lx = config->GetMeshBoxLength(0); + Ly = config->GetMeshBoxLength(1); + + /* Offsets in x and y directions from 0.0. */ + Ox = config->GetMeshBoxOffset(0); + Oy = config->GetMeshBoxOffset(1); + + /* Polynomial degree of the solution. */ + nPolySol = config->GetMeshBoxPSolFEM(); + + /*--- Compute and store the interior elements, points, and surface elements + for this rank, for which simple analytic formulae can be used. ---*/ + ComputeRectangularVolumeConnectivity(); + ComputeRectangularPointCoordinates(); + ComputeRectangularSurfaceConnectivity(); +} + +CRectangularMeshReaderFEM::~CRectangularMeshReaderFEM() = default; + +void CRectangularMeshReaderFEM::ComputeRectangularPointCoordinates() { + + /*--- Set the global count of points based on the grid dimensions. ---*/ + numberOfGlobalPoints = nNode*mNode; + + /*--- Loop over the local elements to determine the global + point IDs to be stored on this rank. --*/ + unsigned long ind = 0; + for(unsigned long i=0; i::iterator lastNode; + lastNode = unique(globalPointIDs.begin(), globalPointIDs.end()); + globalPointIDs.erase(lastNode, globalPointIDs.end()); + + /*--- Determine the number of locally stored points. ---*/ + numberOfLocalPoints = globalPointIDs.size(); + + /*--- Allocate the memory for the locally stored points. ---*/ + localPointCoordinates.resize(dimension); + for (int k = 0; k < dimension; k++) + localPointCoordinates[k].resize(numberOfLocalPoints); + + /*--- Loop over the locally stored points. ---*/ + for(unsigned long i=0; i(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[0].push_back(KindBound); // VTK type. + surfaceElementConnectivity[0].push_back(1); // Poly degree grid. + surfaceElementConnectivity[0].push_back(2); // Number of grid DOFs. + surfaceElementConnectivity[0].push_back(iNode); // Global surface element ID. + surfaceElementConnectivity[0].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[0].push_back(iNode); + surfaceElementConnectivity[0].push_back(iNode+1); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[0]; + } + } + + /*--- Loop over all faces on the xMax (= iMax) boundary. ---*/ + markerNames[1] = "x_plus"; + + for(unsigned long jNode = 0; jNode < mNode-1; ++jNode) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = jNode*nElemI + nElemI-1; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[1].push_back(KindBound); // VTK type. + surfaceElementConnectivity[1].push_back(1); // Poly degree grid. + surfaceElementConnectivity[1].push_back(2); // Number of grid DOFs. + surfaceElementConnectivity[1].push_back(jNode); // Global surface element ID. + surfaceElementConnectivity[1].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[1].push_back(jNode*nNode + (nNode-1)); + surfaceElementConnectivity[1].push_back((jNode+1)*nNode + (nNode-1)); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[1]; + } + } + + /*--- Loop over all faces on the yMax (= jMax) boundary. ---*/ + markerNames[2] = "y_plus"; + + for (unsigned long iNode = 0; iNode < nNode-1; ++iNode) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = (mNode-2)*nElemI + iNode; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[2].push_back(KindBound); // VTK type. + surfaceElementConnectivity[2].push_back(1); // Poly degree grid. + surfaceElementConnectivity[2].push_back(2); // Number of grid DOFs. + surfaceElementConnectivity[2].push_back(iNode); // Global surface element ID. + surfaceElementConnectivity[2].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[2].push_back((mNode-1)*nNode + iNode+1); + surfaceElementConnectivity[2].push_back((mNode-1)*nNode + iNode); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[2]; + } + } + + /*--- Loop over all faces on the xMin (= iMin) boundary. ---*/ + markerNames[3] = "x_minus"; + + for(unsigned long jNode = 0; jNode < mNode-1; ++jNode) { + + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = jNode*nElemI; + if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { + + /*--- The corresponding volume element is stored on this rank, + hence store the surface element as well. ---*/ + surfaceElementConnectivity[3].push_back(KindBound); // VTK type. + surfaceElementConnectivity[3].push_back(1); // Poly degree grid. + surfaceElementConnectivity[3].push_back(2); // Number of grid DOFs. + surfaceElementConnectivity[3].push_back(jNode); // Global surface element ID. + surfaceElementConnectivity[3].push_back(globalElemID); // Global volume element ID. + + surfaceElementConnectivity[3].push_back((jNode+1)*nNode); + surfaceElementConnectivity[3].push_back(jNode*nNode); + + /*--- Update the number of surface elements for this marker. ---*/ + ++numberOfLocalSurfaceElements[3]; + } + } +} diff --git a/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp index 971fe37fbbd..59d6bb74cfc 100644 --- a/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp @@ -61,6 +61,8 @@ CRectangularMeshReaderFVM::CRectangularMeshReaderFVM(const CConfig* val_config, ComputeRectangularSurfaceConnectivity(); } +CRectangularMeshReaderFVM::~CRectangularMeshReaderFVM() = default; + void CRectangularMeshReaderFVM::ComputeRectangularPointCoordinates() { /* Set the global count of points based on the grid dimensions. */ numberOfGlobalPoints = (nNode) * (mNode); diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp index 845221356cb..1802cc9233e 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp @@ -28,7 +28,8 @@ #include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderBase.hpp" -CSU2ASCIIMeshReaderBase::CSU2ASCIIMeshReaderBase(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CSU2ASCIIMeshReaderBase::CSU2ASCIIMeshReaderBase(CConfig* val_config, unsigned short val_iZone, + unsigned short val_nZone) : CMeshReaderBase(val_config, val_iZone, val_nZone), myZone(val_iZone), nZones(val_nZone), diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp index 277c7a983f8..ec310aa35f2 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp @@ -30,7 +30,8 @@ #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp" #include "../../../include/fem/fem_standard_element.hpp" -CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone) +CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, + unsigned short val_nZone) : CSU2ASCIIMeshReaderBase(val_config, val_iZone, val_nZone) { /* Read the basic metadata and perform some basic error checks. */ @@ -49,6 +50,8 @@ CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned sho ReadSurfaceElementConnectivity(); } +CSU2ASCIIMeshReaderFEM::~CSU2ASCIIMeshReaderFEM() = default; + void CSU2ASCIIMeshReaderFEM::ReadPointCoordinates() { /*--- Loop over the local elements to determine the global @@ -376,4 +379,4 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { /*--- Close the mesh file again. ---*/ mesh_file.close(); -} \ No newline at end of file +} diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp index 96a30abb5e0..71fb595e0cb 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp @@ -28,7 +28,8 @@ #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" -CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) +CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, + unsigned short val_nZone) : CSU2ASCIIMeshReaderBase(val_config, val_iZone, val_nZone) { actuator_disk = (((config->GetnMarker_ActDiskInlet() != 0) || (config->GetnMarker_ActDiskOutlet() != 0)) && ((config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD) || @@ -71,6 +72,8 @@ CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned sho mesh_file.close(); } +CSU2ASCIIMeshReaderFVM::~CSU2ASCIIMeshReaderFVM() = default; + void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { /*--- Actuator disk preprocesing ---*/ diff --git a/Common/src/geometry/meshreader/meson.build b/Common/src/geometry/meshreader/meson.build index 6d994fb8420..543bdfcf97a 100644 --- a/Common/src/geometry/meshreader/meson.build +++ b/Common/src/geometry/meshreader/meson.build @@ -1,9 +1,11 @@ -common_src += files(['CBoxMeshReaderFVM.cpp', +common_src += files(['CBoxMeshReaderFEM.cpp', + 'CBoxMeshReaderFVM.cpp', 'CCGNSElementType.cpp', 'CCGNSMeshReaderBase.cpp', 'CCGNSMeshReaderFEM.cpp', 'CCGNSMeshReaderFVM.cpp', 'CMeshReaderBase.cpp', + 'CRectangularMeshReaderFEM.cpp', 'CRectangularMeshReaderFVM.cpp', 'CSU2ASCIIMeshReaderBase.cpp', 'CSU2ASCIIMeshReaderFEM.cpp', From a9ce2780980bd32df80e30109f668a62399408ee Mon Sep 17 00:00:00 2001 From: vdweide Date: Mon, 3 Feb 2025 17:01:45 +0100 Subject: [PATCH 08/15] Copied the data from the mesh reader to CPhysicalGeometry for the FEM solver --- Common/include/geometry/CPhysicalGeometry.hpp | 21 ++++ .../primal_grid/CPrimalGridBoundFEM.hpp | 13 +- .../geometry/primal_grid/CPrimalGridFEM.hpp | 29 +---- .../src/fem/geometry_structure_fem_part.cpp | 119 ++++++++++++++++++ Common/src/geometry/CPhysicalGeometry.cpp | 28 +++-- .../primal_grid/CPrimalGridBoundFEM.cpp | 37 +++--- .../geometry/primal_grid/CPrimalGridFEM.cpp | 71 +++-------- 7 files changed, 197 insertions(+), 121 deletions(-) diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index 20dba58e52e..2e90f374ca7 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -295,6 +295,13 @@ class CPhysicalGeometry final : public CGeometry { */ void LoadLinearlyPartitionedPoints(CConfig* config, CMeshReaderBase* mesh); + /*! + * \brief Routine to load the grid points from a single zone into the proper SU2 data structures for the FEM solver. + * \param[in] config - definition of the particular problem. + * \param[in] mesh - mesh reader object containing the current zone data. + */ + void LoadLinearlyPartitionedPointsFEM(CConfig *config, CMeshReaderBase *mesh); + /*! * \brief Loads the interior volume elements from the mesh reader object into the primal element data structures. * \param[in] config - definition of the particular problem. @@ -302,6 +309,13 @@ class CPhysicalGeometry final : public CGeometry { */ void LoadLinearlyPartitionedVolumeElements(CConfig* config, CMeshReaderBase* mesh); + /*! + * \brief Loads the interior volume elements from the mesh reader object into the primal element data structures for the FEM solver. + * \param[in] config - definition of the particular problem. + * \param[in] mesh - mesh reader object containing the current zone data. + */ + void LoadLinearlyPartitionedVolumeElementsFEM(CConfig *config, CMeshReaderBase *mesh); + /*! * \brief Loads the boundary elements (markers) from the mesh reader object into the primal element data structures. * \param[in] config - definition of the particular problem. @@ -309,6 +323,13 @@ class CPhysicalGeometry final : public CGeometry { */ void LoadUnpartitionedSurfaceElements(CConfig* config, CMeshReaderBase* mesh); + /*! + * \brief Loads the boundary elements (markers) from the mesh reader object into the primal element data structures for the FEM solver. + * \param[in] config - definition of the particular problem. + * \param[in] mesh - mesh reader object containing the current zone data. + */ + void LoadLinearlyPartitionedSurfaceElementsFEM(CConfig *config, CMeshReaderBase *mesh); + /*! * \brief Prepares the grid point adjacency based on a linearly partitioned mesh object needed by ParMETIS for graph * partitioning in parallel. \param[in] config - Definition of the particular problem. diff --git a/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp b/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp index fd7db594f6f..3a2233246cf 100644 --- a/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp @@ -51,16 +51,9 @@ class CPrimalGridBoundFEM final : public CPrimalGrid { public: /*! * \brief Constructor using data to initialize the boundary element. - * \param[in] val_elemGlobalID - Global boundary element ID of this element. - * \param[in] val_domainElementID - Global ID of the corresponding domain element. - * \param[in] val_VTK_Type - VTK type to indicate the element type - * \param[in] val_nPolyGrid - Polynomial degree to describe the geometry of the element. - * \param[in] val_nDOFsGrid - Number of DOFs used to describe the geometry of the element. - * \param[in] val_nodes - Vector, which contains the global node IDs of the element. - */ - CPrimalGridBoundFEM(unsigned long val_elemGlobalID, unsigned long val_domainElementID, unsigned short val_VTK_Type, - unsigned short val_nPolyGrid, unsigned short val_nDOFsGrid, - std::vector& val_nodes); + * \param[in] dataElem - Meta and connectivity data for this element. + */ + CPrimalGridBoundFEM(const unsigned long *dataElem); /*! * \brief Get the number of nodes that composes a face of an element. diff --git a/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp b/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp index 81c214c78ff..a0cafc9f66e 100644 --- a/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp @@ -53,35 +53,12 @@ class CPrimalGridFEM final : public CPrimalGrid { is (almost) constant. */ public: - /*! - * \brief Constructor using data to initialize the element. - * \param[in] val_elemGlobalID - Global element ID of this element. - * \param[in] val_VTK_Type - VTK type to indicate the element type - * \param[in] val_nPolyGrid - Polynomial degree to describe the geometry of the element. - * \param[in] val_nPolySol - Polynomial degree to describe the solution of the element. - * \param[in] val_nDOFsGrid - Number of DOFs used to describe the geometry of the element. - * \param[in] val_nDOFsSol - Number of DOFs used to describe the solution of the element. - * \param[in] val_offDOfsSol - Global offset of the solution DOFs of the element. - * \param[in] elem_line - istringstream, which contains the grid node numbers of the element. - */ - CPrimalGridFEM(unsigned long val_elemGlobalID, unsigned short val_VTK_Type, unsigned short val_nPolyGrid, - unsigned short val_nPolySol, unsigned short val_nDOFsGrid, unsigned short val_nDOFsSol, - unsigned long val_offDOfsSol, std::istringstream& elem_line); /*! * \brief Constructor using data to initialize the element. - * \param[in] val_elemGlobalID - Global element ID of this element. - * \param[in] val_VTK_Type - VTK type to indicate the element type - * \param[in] val_nPolyGrid - Polynomial degree to describe the geometry of the element. - * \param[in] val_nPolySol - Polynomial degree to describe the solution of the element. - * \param[in] val_nDOFsGrid - Number of DOFs used to describe the geometry of the element. - * \param[in] val_nDOFsSol - Number of DOFs used to describe the solution of the element. - * \param[in] val_offDOfsSol - Global offset of the solution DOFs of the element. - * \param[in] connGrid - Array, which contains the grid node numbers of the element. - */ - CPrimalGridFEM(unsigned long val_elemGlobalID, unsigned short val_VTK_Type, unsigned short val_nPolyGrid, - unsigned short val_nPolySol, unsigned short val_nDOFsGrid, unsigned short val_nDOFsSol, - unsigned long val_offDOfsSol, const unsigned long* connGrid); + * \param[in] dataElem - Meta and connectivity data for this element. + */ + CPrimalGridFEM(const unsigned long *dataElem); /*! * \brief Get the number of nodes that composes a face of an element. diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index c3a3547bf1d..a774b7d78b0 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -360,6 +360,125 @@ void CMatchingFace::Copy(const CMatchingFace& other) { tolForMatching = other.tolForMatching; } +void CPhysicalGeometry::LoadLinearlyPartitionedPointsFEM(CConfig *config, CMeshReaderBase *mesh) { + + /*--- Get the partitioned coordinates and their global IDs from the mesh object. ---*/ + const auto &gridCoords = mesh->GetLocalPointCoordinates(); + const auto &globalPointIDs = mesh->GetGlobalPointIDs(); + + /*--- Initialize point counts and the grid node data structure. ---*/ + + nodes = new CPoint(nPoint, nDim); + + /*--- Loop over the points and set the coordinates and global index. ---*/ + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { + for (unsigned short iDim = 0; iDim < nDim; ++iDim) + nodes->SetCoord(iPoint, iDim, gridCoords[iDim][iPoint]); + nodes->SetGlobalIndex(iPoint, globalPointIDs[iPoint]); + } +} + +void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElementsFEM(CConfig *config, + CMeshReaderBase *mesh) { + + /*--- Reset the global to local element mapping. ---*/ + Global_to_Local_Elem.clear(); + + /*--- Get the volume connectivity from the mesh object. ---*/ + const auto &dataElems = mesh->GetLocalVolumeElementConnectivity(); + + /*--- Allocate space for the interior elements in our SU2 data + structure. Note that we only instantiate our rank's local set. ---*/ + elem = new CPrimalGrid*[nElem] (); + + /*--- Loop over all of the internal, local volumetric elements. ---*/ + unsigned long ind = 0; + for (unsigned long jElem=0; jElemGetNumberOfMarkers(); + config->SetnMarker_All(nMarker); + if (rank == MASTER_NODE) + cout << nMarker << " surface markers." << endl; + + /*--- Create the data structure for boundary elements. ---*/ + bound = new CPrimalGrid**[nMarker]; + nElem_Bound = new unsigned long [nMarker]; + Tag_to_Marker = new string [config->GetnMarker_Max()]; + + /*--- Retrieve the name of the surface markers as well as + the number of surface elements for every marker. ---*/ + const auto §ionNames = mesh->GetMarkerNames(); + const auto &nSurfElemPerMarker = mesh->GetNumberOfSurfaceElementsAllMarkers(); + + /*--- Loop over all sections that we extracted from the grid file + that were identified as boundary element sections so that we can + store those elements into our SU2 data structures. ---*/ + for (int iMarker = 0; iMarker < nMarker; ++iMarker) { + + /*--- Get the string name and set the number of surface elements + for this marker. ---*/ + string Marker_Tag = sectionNames[iMarker]; + nElem_Bound[iMarker] = nSurfElemPerMarker[iMarker]; + + /*--- Allocate the memory of the pointers for the surface + elements for this marker. ---*/ + bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]]; + + /*--- Retrieve the boundary element data for this marker. ---*/ + const auto &dataElems = mesh->GetSurfaceElementConnectivityForMarker(iMarker); + + /*--- Loop over the number of boundary elements for this marker. ---*/ + unsigned long ind = 0; + for (unsigned long jElem=0; jElemGetMarker_CfgFile_TagBound(Marker_Tag)] = Marker_Tag; + config->SetMarker_All_TagBound(iMarker, Marker_Tag); + config->SetMarker_All_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); + config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); + config->SetMarker_All_GeoEval(iMarker, config->GetMarker_CfgFile_GeoEval(Marker_Tag)); + config->SetMarker_All_Designing(iMarker, config->GetMarker_CfgFile_Designing(Marker_Tag)); + config->SetMarker_All_Plotting(iMarker, config->GetMarker_CfgFile_Plotting(Marker_Tag)); + config->SetMarker_All_Analyze(iMarker, config->GetMarker_CfgFile_Analyze(Marker_Tag)); + config->SetMarker_All_ZoneInterface(iMarker, config->GetMarker_CfgFile_ZoneInterface(Marker_Tag)); + config->SetMarker_All_DV(iMarker, config->GetMarker_CfgFile_DV(Marker_Tag)); + config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); + config->SetMarker_All_Deform_Mesh(iMarker, config->GetMarker_CfgFile_Deform_Mesh(Marker_Tag)); + config->SetMarker_All_Fluid_Load(iMarker, config->GetMarker_CfgFile_Fluid_Load(Marker_Tag)); + config->SetMarker_All_PyCustom(iMarker, config->GetMarker_CfgFile_PyCustom(Marker_Tag)); + config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); + config->SetMarker_All_SendRecv(iMarker, NONE); + config->SetMarker_All_Turbomachinery(iMarker, config->GetMarker_CfgFile_Turbomachinery(Marker_Tag)); + config->SetMarker_All_TurbomachineryFlag(iMarker, config->GetMarker_CfgFile_TurbomachineryFlag(Marker_Tag)); + config->SetMarker_All_MixingPlaneInterface(iMarker, config->GetMarker_CfgFile_MixingPlaneInterface(Marker_Tag)); + } +} + void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Initialize the color vector of the elements. ---*/ for (unsigned long i = 0; i < nElem; ++i) elem[i]->SetColor(0); diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index f3cd14e2bd4..b97e6399df2 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -3505,16 +3505,30 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena cout << Global_nElem << " volume elements." << endl; } - /*--- Load the grid points, volume elements, and surface elements - from the mesh object into the proper SU2 data structures. ---*/ + /*--- Make a distinction between the FVM solver and FEM solver how to load + the grid data in the member variables of CPhysicalGeometry. ---*/ + if( fem_solver ) { - LoadLinearlyPartitionedPoints(config, Mesh); - LoadLinearlyPartitionedVolumeElements(config, Mesh); - LoadUnpartitionedSurfaceElements(config, Mesh); + /*--- Load the grid points, volume elements, and surface elements + from the mesh object into the proper SU2 data structures. ---*/ - /*--- Prepare the nodal adjacency structures for ParMETIS. ---*/ + LoadLinearlyPartitionedPointsFEM(config, Mesh); + LoadLinearlyPartitionedVolumeElementsFEM(config, Mesh); + LoadLinearlyPartitionedSurfaceElementsFEM(config, Mesh); + } + else { + + /*--- Load the grid points, volume elements, and surface elements + from the mesh object into the proper SU2 data structures. ---*/ + + LoadLinearlyPartitionedPoints(config, Mesh); + LoadLinearlyPartitionedVolumeElements(config, Mesh); + LoadUnpartitionedSurfaceElements(config, Mesh); - PrepareAdjacency(config); + /*--- Prepare the nodal adjacency structures for ParMETIS. ---*/ + + PrepareAdjacency(config); + } /*--- Now that we have loaded all information from the mesh, delete the mesh reader object. ---*/ diff --git a/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp b/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp index cebb3aa2ebf..562d6471cde 100644 --- a/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp +++ b/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp @@ -27,29 +27,24 @@ #include "../../../include/geometry/primal_grid/CPrimalGridBoundFEM.hpp" -CPrimalGridBoundFEM::CPrimalGridBoundFEM(unsigned long val_elemGlobalID, unsigned long val_domainElementID, - unsigned short val_VTK_Type, unsigned short val_nPolyGrid, - unsigned short val_nDOFsGrid, std::vector& val_nodes) - : CPrimalGrid(true, val_nDOFsGrid, 1) { - /*--- Store the integer data in the member variables of this object. ---*/ - VTK_Type = val_VTK_Type; - - nPolyGrid = val_nPolyGrid; - nDOFsGrid = val_nDOFsGrid; - - boundElemIDGlobal = val_elemGlobalID; - GlobalIndex_DomainElement = val_domainElementID; - - /*--- Copy face structure of the element from val_nodes. ---*/ - - for (unsigned short i = 0; i < nDOFsGrid; i++) Nodes[i] = val_nodes[i]; - - /*--- For a linear quadrilateral the two last node numbers must be swapped, - such that the element numbering is consistent with the FEM solver. ---*/ - - if (nPolyGrid == 1 && VTK_Type == QUADRILATERAL) std::swap(Nodes[2], Nodes[3]); +CPrimalGridBoundFEM::CPrimalGridBoundFEM(const unsigned long *dataElem) + :CPrimalGrid(true, dataElem[2], 1) +{ + + /*--- Store the meta data for this element. ---*/ + VTK_Type = (unsigned short) dataElem[0]; + nPolyGrid = (unsigned short) dataElem[1]; + nDOFsGrid = (unsigned short) dataElem[2]; + boundElemIDGlobal = dataElem[3]; + GlobalIndex_DomainElement = dataElem[4]; + + /*--- Allocate the memory for the global nodes of the element to define + the geometry and copy them from val_nodes. ---*/ + for(unsigned short i=0; i> Nodes[i]; - - /*--- If a linear element is used, the node numbering for non-simplices - must be adapted. The reason is that compatability with the original - SU2 format is maintained for linear elements, but for the FEM solver - the nodes of the elements are stored row-wise. ---*/ - if (nPolyGrid == 1) { - switch (VTK_Type) { - case QUADRILATERAL: - std::swap(Nodes[2], Nodes[3]); - break; - - case HEXAHEDRON: - std::swap(Nodes[2], Nodes[3]); - std::swap(Nodes[6], Nodes[7]); - break; - - case PYRAMID: - std::swap(Nodes[2], Nodes[3]); - break; - } - } -} - -CPrimalGridFEM::CPrimalGridFEM(unsigned long val_elemGlobalID, unsigned short val_VTK_Type, - unsigned short val_nPolyGrid, unsigned short val_nPolySol, unsigned short val_nDOFsGrid, - unsigned short val_nDOFsSol, unsigned long val_offDOfsSol, const unsigned long* connGrid) - : CPrimalGrid(true, val_nDOFsGrid, nFacesOfElementType(val_VTK_Type)) { - /*--- Store the integer data in the member variables of this object. ---*/ - VTK_Type = val_VTK_Type; - nFaces = nFacesOfElementType(VTK_Type); - - nPolyGrid = val_nPolyGrid; - nPolySol = val_nPolySol; - nDOFsGrid = val_nDOFsGrid; - nDOFsSol = val_nDOFsSol; - - elemIDGlobal = val_elemGlobalID; - offsetDOFsSolGlobal = val_offDOfsSol; - - /*--- Copy face structure of the element from connGrid. ---*/ - for (unsigned short i = 0; i < nDOFsGrid; i++) Nodes[i] = connGrid[i]; + for(unsigned short i=0; i Date: Tue, 4 Feb 2025 19:16:25 +0100 Subject: [PATCH 09/15] Bug fixes. It seems to be working in sequential mode --- .../geometry/primal_grid/CPrimalGridFEM.hpp | 3 +- Common/src/fem/fem_geometry_structure.cpp | 20 +- .../src/fem/geometry_structure_fem_part.cpp | 198 ++++++++++-------- .../geometry/primal_grid/CPrimalGridFEM.cpp | 7 +- 4 files changed, 127 insertions(+), 101 deletions(-) diff --git a/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp b/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp index a0cafc9f66e..5caa92e0d87 100644 --- a/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp @@ -57,8 +57,9 @@ class CPrimalGridFEM final : public CPrimalGrid { /*! * \brief Constructor using data to initialize the element. * \param[in] dataElem - Meta and connectivity data for this element. + * \param[in,out] offsetDOFs - The offset of the solution DOFs for this element. */ - CPrimalGridFEM(const unsigned long *dataElem); + CPrimalGridFEM(const unsigned long *dataElem, unsigned long &offsetSolDOFs); /*! * \brief Get the number of nodes that composes a face of an element. diff --git a/Common/src/fem/fem_geometry_structure.cpp b/Common/src/fem/fem_geometry_structure.cpp index e671a2d0265..5a7db7445a9 100644 --- a/Common/src/fem/fem_geometry_structure.cpp +++ b/Common/src/fem/fem_geometry_structure.cpp @@ -25,6 +25,7 @@ * License along with SU2. If not, see . */ +#include "../../include/toolboxes/CLinearPartitioner.hpp" #include "../../include/fem/fem_geometry_structure.hpp" #include "../../include/geometry/primal_grid/CPrimalGridFEM.hpp" #include "../../include/geometry/primal_grid/CPrimalGridBoundFEM.hpp" @@ -221,6 +222,9 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /*--- Allocate the memory for blasFunctions. ---*/ blasFunctions = new CBlasStructure; + /*--- Define the linear partitioning of the elements. ---*/ + CLinearPartitioner elemPartitioner(Global_nElem, 0); + /*--- The new FEM mesh class has the same problem dimension/zone. ---*/ nDim = geometry->GetnDim(); nZone = geometry->GetnZone(); @@ -374,13 +378,14 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Loop over the local boundary elements in geometry for this marker. */ for (unsigned long i = 0; i < geometry->GetnElem_Bound(iMarker); ++i) { /* Determine the local ID of the corresponding domain element. */ - unsigned long elemID = geometry->bound[iMarker][i]->GetDomainElement() - geometry->beg_node[rank]; + unsigned long elemID = geometry->bound[iMarker][i]->GetDomainElement() + - elemPartitioner.GetFirstIndexOnRank(rank); /* Determine to which rank this boundary element must be sent. That is the same as its corresponding domain element. Update the corresponding index in longSendBuf. */ int ind = (int)geometry->elem[elemID]->GetColor(); - map::const_iterator MI = rankToIndCommBuf.find(ind); + const auto MI = rankToIndCommBuf.find(ind); ind = MI->second; ++longSendBuf[ind][indLongBuf[ind]]; @@ -667,8 +672,8 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { stored in cumulative storage format. */ vector nElemPerRankOr(size + 1); - for (int i = 0; i < size; ++i) nElemPerRankOr[i] = geometry->beg_node[i]; - nElemPerRankOr[size] = geometry->end_node[size - 1]; + for (int i = 0; i < size; ++i) nElemPerRankOr[i] = elemPartitioner.GetFirstIndexOnRank(i); + nElemPerRankOr[size] = Global_nElem; /* Determine to which ranks I have to send messages to find out the information of the halos stored on this rank. */ @@ -803,11 +808,10 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Determine the local index of the element in the original partitioning. Check if the index is valid. */ - const long localID = globalID - geometry->beg_node[rank]; - if (localID < 0 || localID >= (long)geometry->nPointLinear[rank]) { + const long localID = globalID - elemPartitioner.GetFirstIndexOnRank(rank); + if(elemPartitioner.GetRankContainingIndex(globalID) != static_cast(rank)) { ostringstream message; - message << localID << " " << geometry->nPointLinear[rank] << endl; - message << "Invalid local element ID"; + message << "Invalid local element ID: " << localID; SU2_MPI::Error(message.str(), CURRENT_FUNCTION); } diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index a774b7d78b0..8d0dc218562 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -25,6 +25,7 @@ * License along with SU2. If not, see . */ +#include "../../include/toolboxes/CLinearPartitioner.hpp" #include "../../include/geometry/CPhysicalGeometry.hpp" #include "../../include/fem/fem_standard_element.hpp" #include "../../include/geometry/primal_grid/CPrimalGridFEM.hpp" @@ -393,11 +394,12 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElementsFEM(CConfig *config /*--- Loop over all of the internal, local volumetric elements. ---*/ unsigned long ind = 0; + unsigned long offsetSolDOFs = 0; for (unsigned long jElem=0; jElem nSolDOFsPerRank(size); + SU2_MPI::Allgather(&offsetSolDOFs, 1, MPI_UNSIGNED_LONG, nSolDOFsPerRank.data(), + 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); + + /* Determine the offset for the DOFs on this rank. */ + unsigned long offsetRank = 0; + for (int i = 0; i < rank; ++i) offsetRank += nSolDOFsPerRank[i]; + + /* Loop over the local elements to correct the global offset of the DOFs. */ + for (unsigned long jElem=0; jElemAddOffsetGlobalDOFs(offsetRank); +#endif } void CPhysicalGeometry::LoadLinearlyPartitionedSurfaceElementsFEM(CConfig *config, @@ -498,7 +516,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { CFaceOfElement thisFace; thisFace.nCornerPoints = nPointsPerFace[i]; for (unsigned short j = 0; j < nPointsPerFace[i]; ++j) thisFace.cornerPoints[j] = faceConn[i][j]; - thisFace.elemID0 = beg_node[rank] + k; + thisFace.elemID0 = elem[k]->GetGlobalElemID(); thisFace.nPolySol0 = elem[k]->GetNPolySol(); thisFace.nDOFsElem0 = elem[k]->GetNDOFsSol(); thisFace.elemType0 = elem[k]->GetVTK_Type(); @@ -857,24 +875,27 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { map mapExternalElemIDToTimeLevel; DetermineTimeLevelElements(config, localFaces, mapExternalElemIDToTimeLevel); + /*--- Define the linear partitioning of the elements. ---*/ + CLinearPartitioner elemPartitioner(Global_nElem, 0); + /*--- Determine the ownership of the internal faces, i.e. which adjacent element is responsible for computing the fluxes through the face. ---*/ for (unsigned long i = 0; i < nFacesLoc; ++i) { /* Check for a matching face. */ if (localFaces[i].elemID1 < Global_nElem) { - /* Determine the time level for both elements. Elem0 is always owned, while - elem1 is either owned or external. The data for external elements is - stored in mapExternalElemIDToTimeLevel. */ - unsigned long elemID0 = localFaces[i].elemID0 - beg_node[rank]; - unsigned short timeLevel0 = elem[elemID0]->GetTimeLevel(); + /*--- Determine the time level of Elem0, which is always owned. ---*/ + const unsigned long elemID0 = localFaces[i].elemID0 - elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned short timeLevel0 = elem[elemID0]->GetTimeLevel(); + + /*--- Determine the time level of Elem1, which is either owned or + external. Hence a distinction must be made. ---*/ unsigned short timeLevel1; - if (localFaces[i].elemID1 >= beg_node[rank] && localFaces[i].elemID1 < beg_node[rank] + nElem) { - unsigned long elemID1 = localFaces[i].elemID1 - beg_node[rank]; + if(elemPartitioner.GetRankContainingIndex(localFaces[i].elemID1) == static_cast(rank)) { + const unsigned long elemID1 = localFaces[i].elemID1 - elemPartitioner.GetFirstIndexOnRank(rank); timeLevel1 = elem[elemID1]->GetTimeLevel(); } else { - map::const_iterator MI; - MI = mapExternalElemIDToTimeLevel.find(localFaces[i].elemID1); + const auto MI = mapExternalElemIDToTimeLevel.find(localFaces[i].elemID1); if (MI == mapExternalElemIDToTimeLevel.end()) SU2_MPI::Error("Entry not found in mapExternalElemIDToTimeLevel", CURRENT_FUNCTION); timeLevel1 = MI->second.short0; @@ -924,7 +945,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { CFaceOfElement thisFace; thisFace.nCornerPoints = nPointsPerFace[i]; for (unsigned short j = 0; j < nPointsPerFace[i]; ++j) thisFace.cornerPoints[j] = faceConn[i][j]; - thisFace.elemID0 = beg_node[rank] + k; + thisFace.elemID0 = k + elemPartitioner.GetFirstIndexOnRank(rank); thisFace.nPolySol0 = elem[k]->GetNPolySol(); thisFace.nDOFsElem0 = elem[k]->GetNDOFsSol(); @@ -953,12 +974,19 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { of the graph. First the faces. ---*/ vector > adjacency(nElem, vector(0)); for (unsigned long i = 0; i < nFacesLoc; ++i) { - long ii = localFaces[i].elemID0 - beg_node[rank]; - adjacency[ii].push_back(localFaces[i].elemID1); + /*--- Determine the local index of elem0, which is always stored locally, + and add elemID1 to the adjacency list. ---*/ + const unsigned long elem0 = localFaces[i].elemID0 - elemPartitioner.GetFirstIndexOnRank(rank); + adjacency[elem0].push_back(localFaces[i].elemID1); + + /*--- Check if this is not a periodic face and if the second element is + also a local element. If so, add elemID0 to the adjacency list ---*/ if (localFaces[i].periodicIndex == 0) { - ii = localFaces[i].elemID1 - beg_node[rank]; - if (ii >= 0 && ii < (long)nElem) adjacency[ii].push_back(localFaces[i].elemID0); + if(elemPartitioner.GetRankContainingIndex(localFaces[i].elemID1) == static_cast(rank)) { + const unsigned long elem1 = localFaces[i].elemID1 - elemPartitioner.GetFirstIndexOnRank(rank); + adjacency[elem1].push_back(localFaces[i].elemID0); + } } } @@ -976,7 +1004,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { are present. ParMETIS is not able to deal with self entries, hence they must be removed as well. */ for (unsigned long i = 0; i < nElem; ++i) { - const unsigned long globalElemID = i + beg_node[rank]; + const unsigned long globalElemID = i + + elemPartitioner.GetFirstIndexOnRank(rank); unsigned long nEntriesNew = adjacency[i].size(); for (unsigned long j = 0; j < adjacency[i].size(); ++j) { @@ -999,7 +1027,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { for (unsigned long l = 0; l < nElem_Bound[iMarker]; ++l) { /* Get the global and local element ID adjacent to this boundary face. */ const unsigned long globalElemID = bound[iMarker][l]->GetDomainElement(); - const unsigned long elemID = globalElemID - beg_node[rank]; + const unsigned long elemID = globalElemID - elemPartitioner.GetFirstIndexOnRank(rank); /* Get the number of donor elements for the wall function treatment and the pointer to the array which stores this info. */ @@ -1017,10 +1045,10 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { sort(adjacency[elemID].begin(), adjacency[elemID].end()); /* Check if the donor element is stored locally. */ - if (donors[i] >= beg_node[rank] && donors[i] < beg_node[rank] + nElem) { + if(elemPartitioner.GetRankContainingIndex(donors[i]) == static_cast(rank)) { /* Donor is stored locally. Add the entry to the graph and sort it afterwards. */ - const unsigned long localDonorID = donors[i] - beg_node[rank]; + const unsigned long localDonorID = donors[i] - elemPartitioner.GetFirstIndexOnRank(rank); adjacency[localDonorID].push_back(globalElemID); sort(adjacency[localDonorID].begin(), adjacency[localDonorID].end()); } else { @@ -1042,18 +1070,10 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { vector sendToRank(size, 0); for (unsigned long i = 0; i < additionalExternalEntriesGraph.size(); i += 2) { - /* Determine the rank where this external is stored. */ - const unsigned long elemID = additionalExternalEntriesGraph[i]; - int rankElem; - if (elemID >= beg_node[size - 1]) - rankElem = size - 1; - else { - const unsigned long* low; - low = lower_bound(beg_node, beg_node + size, elemID); - rankElem = low - beg_node; - if (*low > elemID) --rankElem; - } + /*--- Determine the rank where this external is stored and update + the corresponding communication buffers accordingly. ---*/ + const unsigned long rankElem = elemPartitioner.GetRankContainingIndex(additionalExternalEntriesGraph[i]); sendBufsGraphData[rankElem].push_back(additionalExternalEntriesGraph[i]); sendBufsGraphData[rankElem].push_back(additionalExternalEntriesGraph[i + 1]); @@ -1099,7 +1119,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /* Loop over the contents of the receive buffer and update the graph accordingly. */ for (int j = 0; j < sizeMess; j += 2) { - const unsigned long elemID = recvBuf[j] - beg_node[rank]; + const unsigned long elemID = recvBuf[j] - elemPartitioner.GetFirstIndexOnRank(rank); adjacency[elemID].push_back(recvBuf[j + 1]); sort(adjacency[elemID].begin(), adjacency[elemID].end()); } @@ -1945,6 +1965,9 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig* config) { /*--- the local elements. ---*/ /*--------------------------------------------------------------------------*/ + /*--- Define the linear partitioning of the elements. ---*/ + CLinearPartitioner elemPartitioner(Global_nElem, 0); + /* Define the vectors, which store the boundary marker, boundary element ID and exchange coordinates for the integration points for which no donor element was found in the locally stored volume elements. */ @@ -1972,7 +1995,7 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig* config) { /* Easier storage of the element type, the corresponding volume element and the polynomial degree for the solution and grid. */ const unsigned short VTK_Type = bound[iMarker][l]->GetVTK_Type(); - const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - beg_node[rank]; + const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short nPolyGrid = bound[iMarker][l]->GetNPolyGrid(); const unsigned short nPolySol = elem[elemID]->GetNPolySol(); const unsigned short VTK_Elem = elem[elemID]->GetVTK_Type(); @@ -2403,6 +2426,10 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig* config) { void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector& localFaces, map& mapExternalElemIDToTimeLevel) { + + /*--- Define the linear partitioning of the elements. ---*/ + CLinearPartitioner elemPartitioner(Global_nElem, 0); + /*--------------------------------------------------------------------------*/ /*--- Step 1: Initialize the map mapExternalElemIDToTimeLevel. ---*/ /*--------------------------------------------------------------------------*/ @@ -2412,7 +2439,11 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector for (auto FI = localFaces.begin(); FI != localFaces.end(); ++FI) { if (FI->elemID1 < Global_nElem) { // Safeguard against non-matching faces. - if (FI->elemID1 < beg_node[rank] || FI->elemID1 >= beg_node[rank] + nElem) { + /*--- Check for external element. This is done by checking the + local elements and if it is not found, it is an external. ---*/ + const auto UMI = Global_to_Local_Elem.find(FI->elemID1); + if(UMI == Global_to_Local_Elem.end()) { + /* This element is an external element. Store it in the map mapExternalElemIDToTimeLevel if not already done so. */ map::iterator MI; @@ -2439,30 +2470,24 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector const unsigned short nDonors = bound[iMarker][l]->GetNDonorsWallFunctions(); const unsigned long* donors = bound[iMarker][l]->GetDonorsWallFunctions(); - /* Loop over the number of donors and add the externals to - mapExternalElemIDToTimeLevel, if not already present. */ - for (unsigned short i = 0; i < nDonors; ++i) { - if (donors[i] < beg_node[rank] || donors[i] >= beg_node[rank] + nElem) { - map::iterator MI; - MI = mapExternalElemIDToTimeLevel.find(donors[i]); + /*--- Loop over the number of donors for this boundary element. ---*/ + for(unsigned short i=0; i= beg_node[size - 1]) - rankDonor = size - 1; - else { - const unsigned long* low; - low = lower_bound(beg_node, beg_node + size, donors[i]); - - rankDonor = (int)(low - beg_node); - if (*low > donors[i]) --rankDonor; - } + /*--- The reverse connection may not be present either. Store the global + ID of this element in the send buffers for the additional + externals. ---*/ + const unsigned long rankDonor = elemPartitioner.GetRankContainingIndex(donors[i]); sendBufAddExternals[rankDonor].push_back(bound[iMarker][l]->GetDomainElement()); recvFromRank[rankDonor] = 1; @@ -2622,20 +2647,10 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector recvFromRank.assign(size, 0); for (MI = mapExternalElemIDToTimeLevel.begin(); MI != mapExternalElemIDToTimeLevel.end(); ++MI) { - /* Determine the rank where this external is stored. */ - const unsigned long elemID = MI->first; - int rankElem; - if (elemID >= beg_node[size - 1]) - rankElem = size - 1; - else { - const unsigned long* low; - low = lower_bound(beg_node, beg_node + size, elemID); - - rankElem = low - beg_node; - if (*low > elemID) --rankElem; - } - /* Set the corresponding index of recvFromRank to 1. */ + /*--- Determine the rank where this external is stored and set + the corresponding index of recvFromRank to 1. ---*/ + const unsigned long rankElem = elemPartitioner.GetRankContainingIndex(MI->first); recvFromRank[rankElem] = 1; } @@ -2658,18 +2673,9 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector for (MI = mapExternalElemIDToTimeLevel.begin(); MI != mapExternalElemIDToTimeLevel.end(); ++MI) { const unsigned long elemID = MI->first; - int rankElem; - if (elemID >= beg_node[size - 1]) - rankElem = size - 1; - else { - const unsigned long* low; - low = lower_bound(beg_node, beg_node + size, elemID); - - rankElem = low - beg_node; - if (*low > elemID) --rankElem; - } + const unsigned long rankElem = elemPartitioner.GetRankContainingIndex(elemID); - map::const_iterator MRI = mapRankToIndRecv.find(rankElem); + const auto MRI = mapRankToIndRecv.find(rankElem); recvElem[MRI->second].push_back(elemID); } @@ -2705,7 +2711,8 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector SU2_MPI::Recv(sendElem[i].data(), sizeMess, MPI_UNSIGNED_LONG, sendRank[i], rank, SU2_MPI::GetComm(), &status); - for (int j = 0; j < sizeMess; ++j) sendElem[i][j] -= beg_node[rank]; + for (int j = 0; j < sizeMess; ++j) + sendElem[i][j] -= elemPartitioner.GetFirstIndexOnRank(rank); } /* Complete the non-blocking sends. Synchronize the processors afterwards, @@ -2796,7 +2803,8 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector for (unsigned short iMarker = 0; iMarker < nMarker; ++iMarker) { for (unsigned long l = 0; l < nElem_Bound[iMarker]; ++l) { /* Determine the ID of the adjacent element. */ - const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - beg_node[rank]; + const unsigned long elemID = bound[iMarker][l]->GetDomainElement() + - elemPartitioner.GetFirstIndexOnRank(rank); /* Get the number of donor elements for the wall function treatment and the pointer to the array which stores this info. */ @@ -2805,11 +2813,14 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector /* Loop over the number of donors and check the time levels. */ for (unsigned short i = 0; i < nDonors; ++i) { + /* Determine the status of the donor element. */ - if (donors[i] >= beg_node[rank] && donors[i] < beg_node[rank] + nElem) { + if(elemPartitioner.GetRankContainingIndex(donors[i]) == static_cast(rank)) { + /* Donor is stored locally. Determine its local ID and get the time levels of both elements. */ - const unsigned long donorID = donors[i] - beg_node[rank]; + const unsigned long donorID = donors[i] + - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short timeLevelB = elem[elemID]->GetTimeLevel(); const unsigned short timeLevelD = elem[donorID]->GetTimeLevel(); const unsigned short timeLevel = min(timeLevelB, timeLevelD); @@ -2860,15 +2871,16 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector if (FI->elemID1 < Global_nElem) { /* Local element ID of the first element. Per definition this is always a locally stored element. Also store its time level. */ - const unsigned long elemID0 = FI->elemID0 - beg_node[rank]; + const unsigned long elemID0 = FI->elemID0 + - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short timeLevel0 = elem[elemID0]->GetTimeLevel(); /* Determine the status of the second element. */ - if (FI->elemID1 >= beg_node[rank] && FI->elemID1 < beg_node[rank] + nElem) { + if(elemPartitioner.GetRankContainingIndex(FI->elemID1) == static_cast(rank)) { /* Both elements are stored locally. Determine the local element of the second element and determine the minimum time level. */ - const unsigned long elemID1 = FI->elemID1 - beg_node[rank]; + const unsigned long elemID1 = FI->elemID1 - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short timeLevel1 = elem[elemID1]->GetTimeLevel(); const unsigned short timeLevel = min(timeLevel0, timeLevel1); @@ -3016,6 +3028,10 @@ void CPhysicalGeometry::ComputeFEMGraphWeights(CConfig* config, const vector >& adjacency, const map& mapExternalElemIDToTimeLevel, vector& vwgt, vector >& adjwgt) { + + /*--- Define the linear partitioning of the elements. ---*/ + CLinearPartitioner elemPartitioner(Global_nElem, 0); + /*--- Determine the maximum time level that occurs in the grid. ---*/ unsigned short maxTimeLevel = 0; for (unsigned long i = 0; i < nElem; ++i) maxTimeLevel = max(maxTimeLevel, elem[i]->GetTimeLevel()); @@ -3077,7 +3093,7 @@ void CPhysicalGeometry::ComputeFEMGraphWeights(CConfig* config, const vectorGetVTK_Type(); - const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - beg_node[rank]; + const unsigned long elemID = bound[iMarker][l]->GetDomainElement() + - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short nPolySol = elem[elemID]->GetNPolySol(); const unsigned short VTK_Type_Elem = elem[elemID]->GetVTK_Type(); const bool JacIsConstant = bound[iMarker][l]->GetJacobianConsideredConstant(); @@ -3277,17 +3294,16 @@ void CPhysicalGeometry::ComputeFEMGraphWeights(CConfig* config, const vector= beg_node[rank] && adjacency[i][j] < beg_node[rank] + nElem) { + if(elemPartitioner.GetRankContainingIndex(adjacency[i][j]) == static_cast(rank)) { /* Locally stored element. Determine its local ID and set the time level and number of solution DOFs. */ - unsigned long elemID1 = adjacency[i][j] - beg_node[rank]; + unsigned long elemID1 = adjacency[i][j] - elemPartitioner.GetFirstIndexOnRank(rank); timeLevel1 = elem[elemID1]->GetTimeLevel(); nDOFs1 = elem[elemID1]->GetNDOFsSol(); } else { /* The neighbor is an external element. Find it in mapExternalElemIDToTimeLevel and set the time level and number of solution DOFs accordingly. */ - map::const_iterator MI; - MI = mapExternalElemIDToTimeLevel.find(adjacency[i][j]); + const auto MI = mapExternalElemIDToTimeLevel.find(adjacency[i][j]); if (MI == mapExternalElemIDToTimeLevel.end()) SU2_MPI::Error("Entry not found in mapExternalElemIDToTimeLevel", CURRENT_FUNCTION); timeLevel1 = MI->second.short0; diff --git a/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp b/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp index c4d29007946..122127c2c92 100644 --- a/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp +++ b/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp @@ -28,7 +28,7 @@ #include "../../../include/geometry/primal_grid/CPrimalGridFEM.hpp" #include "../../../include/fem/fem_standard_element.hpp" -CPrimalGridFEM::CPrimalGridFEM(const unsigned long *dataElem) +CPrimalGridFEM::CPrimalGridFEM(const unsigned long *dataElem, unsigned long &offsetSolDOFs) : CPrimalGrid(true, dataElem[3], nFacesOfElementType(dataElem[0])) { /*--- Store the meta data for this element. ---*/ @@ -39,6 +39,11 @@ CPrimalGridFEM::CPrimalGridFEM(const unsigned long *dataElem) nDOFsSol = CFEMStandardElementBase::GetNDOFsStatic(VTK_Type, nPolySol); elemIDGlobal = dataElem[4]; + offsetDOFsSolGlobal = offsetSolDOFs; + offsetSolDOFs += nDOFsSol; + + nFaces = nFacesOfElementType(VTK_Type); + /*--- Allocate the memory for the global nodes of the element to define the geometry and copy the data from dataElem. ---*/ From 6b617b177eb44e4eeadc10fa018f039329e5eaff Mon Sep 17 00:00:00 2001 From: vdweide Date: Wed, 5 Feb 2025 15:46:24 +0100 Subject: [PATCH 10/15] Bug fixes to make things work in parallel --- Common/src/fem/fem_geometry_structure.cpp | 6 +++--- Common/src/fem/geometry_structure_fem_part.cpp | 4 ++-- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/Common/src/fem/fem_geometry_structure.cpp b/Common/src/fem/fem_geometry_structure.cpp index 5a7db7445a9..1f1c7495b2c 100644 --- a/Common/src/fem/fem_geometry_structure.cpp +++ b/Common/src/fem/fem_geometry_structure.cpp @@ -223,6 +223,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { blasFunctions = new CBlasStructure; /*--- Define the linear partitioning of the elements. ---*/ + Global_nElem = geometry->GetGlobal_nElem(); CLinearPartitioner elemPartitioner(Global_nElem, 0); /*--- The new FEM mesh class has the same problem dimension/zone. ---*/ @@ -671,9 +672,8 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Determine the number of elements per rank of the originally partitioned grid stored in cumulative storage format. */ vector nElemPerRankOr(size + 1); - - for (int i = 0; i < size; ++i) nElemPerRankOr[i] = elemPartitioner.GetFirstIndexOnRank(i); - nElemPerRankOr[size] = Global_nElem; + for (int i = 0; i <= size; ++i) + nElemPerRankOr[i] = elemPartitioner.GetCumulativeSizeBeforeRank(i); /* Determine to which ranks I have to send messages to find out the information of the halos stored on this rank. */ diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index 8d0dc218562..5bbf731eef8 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -1162,8 +1162,8 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Determine the array, which stores the distribution of the graph nodes over the ranks. ---*/ vector vtxdist(size + 1); - vtxdist[0] = 0; - for (int i = 0; i < size; ++i) vtxdist[i + 1] = (idx_t)end_node[i]; + for (int i = 0; i <= size; ++i) + vtxdist[i] = static_cast(elemPartitioner.GetCumulativeSizeBeforeRank(i)); /* Create the array xadjPar, which contains the number of edges for each vertex of the graph in ParMETIS format. */ From 020f87a203f07a99ac1a32869ca874df0b4a2d7e Mon Sep 17 00:00:00 2001 From: vdweide Date: Wed, 5 Feb 2025 15:52:24 +0100 Subject: [PATCH 11/15] Result of running pre-commit --- Common/include/geometry/CPhysicalGeometry.hpp | 21 +- .../geometry/meshreader/CBoxMeshReaderFEM.hpp | 11 +- .../geometry/meshreader/CCGNSElementType.hpp | 203 +-- .../meshreader/CCGNSMeshReaderFEM.hpp | 24 +- .../geometry/meshreader/CMeshReaderBase.hpp | 20 +- .../meshreader/CSU2ASCIIMeshReaderFEM.hpp | 5 +- .../primal_grid/CPrimalGridBoundFEM.hpp | 2 +- .../geometry/primal_grid/CPrimalGridFEM.hpp | 3 +- Common/src/fem/fem_geometry_structure.cpp | 9 +- .../src/fem/geometry_structure_fem_part.cpp | 113 +- Common/src/geometry/CPhysicalGeometry.cpp | 31 +- .../geometry/meshreader/CBoxMeshReaderFEM.cpp | 215 ++- .../geometry/meshreader/CCGNSElementType.cpp | 1253 +++++++++++------ .../meshreader/CCGNSMeshReaderBase.cpp | 68 +- .../meshreader/CCGNSMeshReaderFEM.cpp | 237 ++-- .../meshreader/CCGNSMeshReaderFVM.cpp | 3 +- .../geometry/meshreader/CMeshReaderBase.cpp | 43 +- .../meshreader/CRectangularMeshReaderFEM.cpp | 120 +- .../meshreader/CSU2ASCIIMeshReaderBase.cpp | 3 +- .../meshreader/CSU2ASCIIMeshReaderFEM.cpp | 183 ++- .../meshreader/CSU2ASCIIMeshReaderFVM.cpp | 3 +- .../primal_grid/CPrimalGridBoundFEM.cpp | 17 +- .../geometry/primal_grid/CPrimalGridFEM.cpp | 18 +- 23 files changed, 1436 insertions(+), 1169 deletions(-) diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index 2e90f374ca7..e6a871bb977 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -285,8 +285,7 @@ class CPhysicalGeometry final : public CGeometry { * \param[in] val_iZone - Domain to be read from the grid file. * \param[in] val_nZone - Total number of domains in the grid file. */ - void Read_Mesh(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, - unsigned short val_nZone); + void Read_Mesh(CConfig* config, const string& val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone); /*! * \brief Routine to load the CGNS grid points from a single zone into the proper SU2 data structures. @@ -300,7 +299,7 @@ class CPhysicalGeometry final : public CGeometry { * \param[in] config - definition of the particular problem. * \param[in] mesh - mesh reader object containing the current zone data. */ - void LoadLinearlyPartitionedPointsFEM(CConfig *config, CMeshReaderBase *mesh); + void LoadLinearlyPartitionedPointsFEM(CConfig* config, CMeshReaderBase* mesh); /*! * \brief Loads the interior volume elements from the mesh reader object into the primal element data structures. @@ -310,11 +309,11 @@ class CPhysicalGeometry final : public CGeometry { void LoadLinearlyPartitionedVolumeElements(CConfig* config, CMeshReaderBase* mesh); /*! - * \brief Loads the interior volume elements from the mesh reader object into the primal element data structures for the FEM solver. - * \param[in] config - definition of the particular problem. - * \param[in] mesh - mesh reader object containing the current zone data. + * \brief Loads the interior volume elements from the mesh reader object into the primal element data structures for + * the FEM solver. \param[in] config - definition of the particular problem. \param[in] mesh - mesh reader object + * containing the current zone data. */ - void LoadLinearlyPartitionedVolumeElementsFEM(CConfig *config, CMeshReaderBase *mesh); + void LoadLinearlyPartitionedVolumeElementsFEM(CConfig* config, CMeshReaderBase* mesh); /*! * \brief Loads the boundary elements (markers) from the mesh reader object into the primal element data structures. @@ -324,11 +323,11 @@ class CPhysicalGeometry final : public CGeometry { void LoadUnpartitionedSurfaceElements(CConfig* config, CMeshReaderBase* mesh); /*! - * \brief Loads the boundary elements (markers) from the mesh reader object into the primal element data structures for the FEM solver. - * \param[in] config - definition of the particular problem. - * \param[in] mesh - mesh reader object containing the current zone data. + * \brief Loads the boundary elements (markers) from the mesh reader object into the primal element data structures + * for the FEM solver. \param[in] config - definition of the particular problem. \param[in] mesh - mesh reader + * object containing the current zone data. */ - void LoadLinearlyPartitionedSurfaceElementsFEM(CConfig *config, CMeshReaderBase *mesh); + void LoadLinearlyPartitionedSurfaceElementsFEM(CConfig* config, CMeshReaderBase* mesh); /*! * \brief Prepares the grid point adjacency based on a linearly partitioned mesh object needed by ParMETIS for graph diff --git a/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp index acfafef6365..f5a0e53934b 100644 --- a/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp +++ b/Common/include/geometry/meshreader/CBoxMeshReaderFEM.hpp @@ -35,10 +35,8 @@ * \brief Reads a 3D box grid into linear partitions for the finite element solver (FEM). * \author: T. Economon, E. van der Weide */ -class CBoxMeshReaderFEM final: public CMeshReaderBase { - -private: - +class CBoxMeshReaderFEM final : public CMeshReaderBase { + private: unsigned long nNode; /*!< \brief Number of grid nodes in the x-direction. */ unsigned long mNode; /*!< \brief Number of grid nodes in the y-direction. */ unsigned long pNode; /*!< \brief Number of grid nodes in the z-direction. */ @@ -71,12 +69,11 @@ class CBoxMeshReaderFEM final: public CMeshReaderBase { */ void ComputeBoxSurfaceConnectivity(); -public: - + public: /*! * \brief Constructor of the CBoxMeshReaderFEM class. */ - CBoxMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); + CBoxMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); /*! * \brief Destructor of the CBoxMeshReaderFEM class. diff --git a/Common/include/geometry/meshreader/CCGNSElementType.hpp b/Common/include/geometry/meshreader/CCGNSElementType.hpp index e081347be1b..fbe944f0114 100644 --- a/Common/include/geometry/meshreader/CCGNSElementType.hpp +++ b/Common/include/geometry/meshreader/CCGNSElementType.hpp @@ -41,19 +41,17 @@ using namespace std; /*! * \class CCGNSElementType * \brief Class used to convert the CGNS format to SU2 format for high order elements. -* \author: E. van der Weide + * \author: E. van der Weide */ class CCGNSElementType { -private: - - vector CGNSTypeStored; /*!< \brief CGNS element types for which the data is stored. */ - vector VTKTypeStored; /*!< \brief VTK type of the element. */ - vector nPolyStored; /*!< \brief Polynomial degree of the element. */ - vector nDOFsStored; /*!< \brief Number of DOFs of the element. */ - vector > SU2ToCGNSStored; /*!< \brief Double vector, which stores the conversion + private: + vector CGNSTypeStored; /*!< \brief CGNS element types for which the data is stored. */ + vector VTKTypeStored; /*!< \brief VTK type of the element. */ + vector nPolyStored; /*!< \brief Polynomial degree of the element. */ + vector nDOFsStored; /*!< \brief Number of DOFs of the element. */ + vector > SU2ToCGNSStored; /*!< \brief Double vector, which stores the conversion from SU2 to CGNS for the type in local numbering. */ -public: - + public: /*--- Standard constructor, nothing to be done. ---*/ CCGNSElementType() = default; @@ -67,13 +65,10 @@ class CCGNSElementType { * \param[in] connCGNS - Array with the connectivity of the element in CGNS format. * \param[out] connSU2 - Vector with the connectivity and meta data in SU2 format. */ - void CGNSToSU2(const ElementType_t val_elemType, - const unsigned long val_globalID, - const cgsize_t *connCGNS, - std::vector &connSU2); - -private: + void CGNSToSU2(const ElementType_t val_elemType, const unsigned long val_globalID, const cgsize_t* connCGNS, + std::vector& connSU2); + private: /*! * \brief Converts the connectivity from CGNS to SU2 for a node. * \param[out] VTK_Type - Corresponding VTK type @@ -81,10 +76,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataNODE(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataNODE(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Bar2 element. @@ -93,10 +86,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataBAR_2(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataBAR_2(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Bar3 element. @@ -105,22 +96,18 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataBAR_3(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataBAR_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); - /*! + /*! * \brief Converts the connectivity from CGNS to SU2 for a Bar4 element. * \param[out] VTK_Type - Corresponding VTK type * \param[out] nPoly - Polynomial degree * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataBAR_4(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataBAR_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Bar5 element. @@ -129,10 +116,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataBAR_5(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataBAR_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tri3 element. @@ -141,10 +126,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTRI_3(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTRI_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tri6 element. @@ -153,10 +136,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTRI_6(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTRI_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tri10 element. @@ -165,10 +146,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTRI_10(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTRI_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tri15 element. @@ -177,10 +156,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTRI_15(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTRI_15(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Quad4 element. @@ -189,10 +166,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataQUAD_4(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataQUAD_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Quad9 element. @@ -201,10 +176,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataQUAD_9(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataQUAD_9(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Quad16 element. @@ -213,10 +186,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataQUAD_16(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataQUAD_16(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Quad25 element. @@ -225,10 +196,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataQUAD_25(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataQUAD_25(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tetra4 element. @@ -237,10 +206,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTETRA_4(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTETRA_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tetra10 element. @@ -249,10 +216,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTETRA_10(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTETRA_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tetra20 element. @@ -261,10 +226,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTETRA_20(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTETRA_20(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Tetra35 element. @@ -273,10 +236,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataTETRA_35(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataTETRA_35(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Pyra5 element. @@ -285,10 +246,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPYRA_5(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPYRA_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Pyra14 element. @@ -297,10 +256,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPYRA_14(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPYRA_14(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Pyra30 element. @@ -309,10 +266,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPYRA_30(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPYRA_30(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Pyra55 element. @@ -321,10 +276,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPYRA_55(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPYRA_55(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Penta6 element. @@ -333,10 +286,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPENTA_6(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPENTA_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Penta18 element. @@ -345,10 +296,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPENTA_18(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPENTA_18(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Penta40 element. @@ -357,10 +306,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPENTA_40(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPENTA_40(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Penta75 element. @@ -369,10 +316,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataPENTA_75(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataPENTA_75(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Hexa8 element. @@ -381,10 +326,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataHEXA_8(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataHEXA_8(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Hexa27 element. @@ -393,10 +336,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataHEXA_27(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataHEXA_27(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Hexa64 element. @@ -405,10 +346,8 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataHEXA_64(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataHEXA_64(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); /*! * \brief Converts the connectivity from CGNS to SU2 for a Hexa125 element. @@ -417,9 +356,7 @@ class CCGNSElementType { * \param[out] nDOFs - Number of DOFs of the element. * \param[out] SU2ToCGNS - Vector containing the mapping from SU2 to CGNS. */ - void CreateDataHEXA_125(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS); + void CreateDataHEXA_125(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS); }; #endif diff --git a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp index a07bf969f4c..cb7fcd404e8 100644 --- a/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp +++ b/Common/include/geometry/meshreader/CCGNSMeshReaderFEM.hpp @@ -37,7 +37,6 @@ */ class CCGNSMeshReaderFEM final : public CCGNSMeshReaderBase { private: - /*! * \brief Communicates the grid points to the MPI rank where they are needed. */ @@ -54,20 +53,18 @@ class CCGNSMeshReaderFEM final : public CCGNSMeshReaderBase { * \param[inout] localElemCount - Counter, which keeps track how many local elements are stored. * \param[inout] localConn - Vector where the connectivity must be stored. */ - void ReadCGNSConnectivityRangeSection(const int val_section, - const unsigned long val_firstIndex, - const unsigned long val_lastIndex, - unsigned long &elemCount, - unsigned long &localElemCount, - vector &localConn); + void ReadCGNSConnectivityRangeSection(const int val_section, const unsigned long val_firstIndex, + const unsigned long val_lastIndex, unsigned long& elemCount, + unsigned long& localElemCount, vector& localConn); -/*! + /*! * \brief Reads the interior volume elements from one section of a CGNS zone into linear partitions across all ranks. */ void ReadCGNSVolumeElementConnectivity(); /*! - * \brief Reads the surface (boundary) elements from one section of a CGNS zone into linear partitions across all ranks. + * \brief Reads the surface (boundary) elements from one section of a CGNS zone into linear partitions across all + * ranks. */ void ReadCGNSSurfaceElementConnectivity(); @@ -78,18 +75,15 @@ class CCGNSMeshReaderFEM final : public CCGNSMeshReaderBase { * \param[out] nSurfElem - Number of local surface elements stored for this surface section. * \param[out] surfConn - Vector to store the connectivity of the surface elements to be stored. */ - void ReadCGNSSurfaceSection(const int val_section, - const vector &localFaces, - unsigned long &nSurfElem, - vector &surfConn); + void ReadCGNSSurfaceSection(const int val_section, const vector& localFaces, unsigned long& nSurfElem, + vector& surfConn); #endif public: - /*! * \brief Constructor of the CCGNSMeshReaderFEM class. */ - CCGNSMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); + CCGNSMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); /*! * \brief Destructor of the CCGNSMeshReaderFEM class. diff --git a/Common/include/geometry/meshreader/CMeshReaderBase.hpp b/Common/include/geometry/meshreader/CMeshReaderBase.hpp index da3f72c48cc..622b48db4c8 100644 --- a/Common/include/geometry/meshreader/CMeshReaderBase.hpp +++ b/Common/include/geometry/meshreader/CMeshReaderBase.hpp @@ -66,16 +66,18 @@ class CMeshReaderBase { unsigned long numberOfMarkers = 0; /*!< \brief Total number of markers contained within the mesh file. */ vector markerNames; /*!< \brief String names for all markers in the mesh file. */ - vector numberOfLocalSurfaceElements; /*!< \brief Vector containing the number of local surface elements. */ + vector + numberOfLocalSurfaceElements; /*!< \brief Vector containing the number of local surface elements. */ vector > surfaceElementConnectivity; /*!< \brief Vector containing the surface element connectivity from the mesh file on a - per-marker basis. For FVM, only the master node reads and stores this connectivity. */ + per-marker basis. For FVM, only the master node reads and stores this connectivity. + */ /*! * \brief Function, which determines the faces of the local volume elements. * \param[out] localFaces - The faces of the locally stored volume elements. */ - void DetermineFacesVolumeElements(vector &localFaces); + void DetermineFacesVolumeElements(vector& localFaces); /*! * \brief Get all the corner points of all the faces of the given element. It must @@ -84,10 +86,8 @@ class CMeshReaderBase { * \param[out] nPointsPerFace - Number of corner points for each of the faces. * \param[out] faceConn - Global IDs of the corner points of the faces. */ - void GetCornerPointsAllFaces(const unsigned long *elemInfo, - unsigned short &numFaces, - unsigned short nPointsPerFace[], - unsigned long faceConn[6][4]); + void GetCornerPointsAllFaces(const unsigned long* elemInfo, unsigned short& numFaces, unsigned short nPointsPerFace[], + unsigned long faceConn[6][4]); public: /*! @@ -110,9 +110,7 @@ class CMeshReaderBase { * \brief Get the global IDs of the local points. * \returns Reference to the vector containing the global points IDs. */ - inline const vector &GetGlobalPointIDs() const { - return globalPointIDs; - } + inline const vector& GetGlobalPointIDs() const { return globalPointIDs; } /*! * \brief Get the local point coordinates (linearly partitioned). @@ -133,7 +131,7 @@ class CMeshReaderBase { * \brief Get the number surface elements for all markers. * \returns Reference to the vector containing the number of surface elements for all markers. */ - inline const vector &GetNumberOfSurfaceElementsAllMarkers() const { + inline const vector& GetNumberOfSurfaceElementsAllMarkers() const { return numberOfLocalSurfaceElements; } diff --git a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp index 3b4759a9301..d92cf336103 100644 --- a/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp +++ b/Common/include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp @@ -50,7 +50,8 @@ class CSU2ASCIIMeshReaderFEM : public CSU2ASCIIMeshReaderBase { void ReadVolumeElementConnectivity(); /*! - * \brief Reads the surface (boundary) elements from one section of an SU2 zone into linear partitions across all ranks. + * \brief Reads the surface (boundary) elements from one section of an SU2 zone into linear partitions across all + * ranks. */ void ReadSurfaceElementConnectivity(); @@ -58,7 +59,7 @@ class CSU2ASCIIMeshReaderFEM : public CSU2ASCIIMeshReaderBase { /*! * \brief Constructor of the CSU2ASCIIMeshReaderFEM class. */ - CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, unsigned short val_nZone); + CSU2ASCIIMeshReaderFEM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone); /*! * \brief Destructor of the CSU2ASCIIMeshReaderFEM class. diff --git a/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp b/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp index 3a2233246cf..3975d1debba 100644 --- a/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGridBoundFEM.hpp @@ -53,7 +53,7 @@ class CPrimalGridBoundFEM final : public CPrimalGrid { * \brief Constructor using data to initialize the boundary element. * \param[in] dataElem - Meta and connectivity data for this element. */ - CPrimalGridBoundFEM(const unsigned long *dataElem); + CPrimalGridBoundFEM(const unsigned long* dataElem); /*! * \brief Get the number of nodes that composes a face of an element. diff --git a/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp b/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp index 5caa92e0d87..77e1a5fc3b9 100644 --- a/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGridFEM.hpp @@ -53,13 +53,12 @@ class CPrimalGridFEM final : public CPrimalGrid { is (almost) constant. */ public: - /*! * \brief Constructor using data to initialize the element. * \param[in] dataElem - Meta and connectivity data for this element. * \param[in,out] offsetDOFs - The offset of the solution DOFs for this element. */ - CPrimalGridFEM(const unsigned long *dataElem, unsigned long &offsetSolDOFs); + CPrimalGridFEM(const unsigned long* dataElem, unsigned long& offsetSolDOFs); /*! * \brief Get the number of nodes that composes a face of an element. diff --git a/Common/src/fem/fem_geometry_structure.cpp b/Common/src/fem/fem_geometry_structure.cpp index 1f1c7495b2c..e5580de752e 100644 --- a/Common/src/fem/fem_geometry_structure.cpp +++ b/Common/src/fem/fem_geometry_structure.cpp @@ -379,8 +379,8 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Loop over the local boundary elements in geometry for this marker. */ for (unsigned long i = 0; i < geometry->GetnElem_Bound(iMarker); ++i) { /* Determine the local ID of the corresponding domain element. */ - unsigned long elemID = geometry->bound[iMarker][i]->GetDomainElement() - - elemPartitioner.GetFirstIndexOnRank(rank); + unsigned long elemID = + geometry->bound[iMarker][i]->GetDomainElement() - elemPartitioner.GetFirstIndexOnRank(rank); /* Determine to which rank this boundary element must be sent. That is the same as its corresponding domain element. @@ -672,8 +672,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Determine the number of elements per rank of the originally partitioned grid stored in cumulative storage format. */ vector nElemPerRankOr(size + 1); - for (int i = 0; i <= size; ++i) - nElemPerRankOr[i] = elemPartitioner.GetCumulativeSizeBeforeRank(i); + for (int i = 0; i <= size; ++i) nElemPerRankOr[i] = elemPartitioner.GetCumulativeSizeBeforeRank(i); /* Determine to which ranks I have to send messages to find out the information of the halos stored on this rank. */ @@ -809,7 +808,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Determine the local index of the element in the original partitioning. Check if the index is valid. */ const long localID = globalID - elemPartitioner.GetFirstIndexOnRank(rank); - if(elemPartitioner.GetRankContainingIndex(globalID) != static_cast(rank)) { + if (elemPartitioner.GetRankContainingIndex(globalID) != static_cast(rank)) { ostringstream message; message << "Invalid local element ID: " << localID; SU2_MPI::Error(message.str(), CURRENT_FUNCTION); diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index 5bbf731eef8..1babb698f7d 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -361,11 +361,10 @@ void CMatchingFace::Copy(const CMatchingFace& other) { tolForMatching = other.tolForMatching; } -void CPhysicalGeometry::LoadLinearlyPartitionedPointsFEM(CConfig *config, CMeshReaderBase *mesh) { - +void CPhysicalGeometry::LoadLinearlyPartitionedPointsFEM(CConfig* config, CMeshReaderBase* mesh) { /*--- Get the partitioned coordinates and their global IDs from the mesh object. ---*/ - const auto &gridCoords = mesh->GetLocalPointCoordinates(); - const auto &globalPointIDs = mesh->GetGlobalPointIDs(); + const auto& gridCoords = mesh->GetLocalPointCoordinates(); + const auto& globalPointIDs = mesh->GetGlobalPointIDs(); /*--- Initialize point counts and the grid node data structure. ---*/ @@ -373,32 +372,28 @@ void CPhysicalGeometry::LoadLinearlyPartitionedPointsFEM(CConfig *config, CMeshR /*--- Loop over the points and set the coordinates and global index. ---*/ for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - for (unsigned short iDim = 0; iDim < nDim; ++iDim) - nodes->SetCoord(iPoint, iDim, gridCoords[iDim][iPoint]); + for (unsigned short iDim = 0; iDim < nDim; ++iDim) nodes->SetCoord(iPoint, iDim, gridCoords[iDim][iPoint]); nodes->SetGlobalIndex(iPoint, globalPointIDs[iPoint]); } } -void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElementsFEM(CConfig *config, - CMeshReaderBase *mesh) { - +void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElementsFEM(CConfig* config, CMeshReaderBase* mesh) { /*--- Reset the global to local element mapping. ---*/ Global_to_Local_Elem.clear(); /*--- Get the volume connectivity from the mesh object. ---*/ - const auto &dataElems = mesh->GetLocalVolumeElementConnectivity(); + const auto& dataElems = mesh->GetLocalVolumeElementConnectivity(); /*--- Allocate space for the interior elements in our SU2 data structure. Note that we only instantiate our rank's local set. ---*/ - elem = new CPrimalGrid*[nElem] (); + elem = new CPrimalGrid*[nElem](); /*--- Loop over all of the internal, local volumetric elements. ---*/ unsigned long ind = 0; unsigned long offsetSolDOFs = 0; - for (unsigned long jElem=0; jElem nSolDOFsPerRank(size); - SU2_MPI::Allgather(&offsetSolDOFs, 1, MPI_UNSIGNED_LONG, nSolDOFsPerRank.data(), - 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); + SU2_MPI::Allgather(&offsetSolDOFs, 1, MPI_UNSIGNED_LONG, nSolDOFsPerRank.data(), 1, MPI_UNSIGNED_LONG, + SU2_MPI::GetComm()); /* Determine the offset for the DOFs on this rank. */ unsigned long offsetRank = 0; for (int i = 0; i < rank; ++i) offsetRank += nSolDOFsPerRank[i]; /* Loop over the local elements to correct the global offset of the DOFs. */ - for (unsigned long jElem=0; jElemAddOffsetGlobalDOFs(offsetRank); + for (unsigned long jElem = 0; jElem < nElem; ++jElem) elem[jElem]->AddOffsetGlobalDOFs(offsetRank); #endif } -void CPhysicalGeometry::LoadLinearlyPartitionedSurfaceElementsFEM(CConfig *config, - CMeshReaderBase *mesh) { - +void CPhysicalGeometry::LoadLinearlyPartitionedSurfaceElementsFEM(CConfig* config, CMeshReaderBase* mesh) { /*--- Store the number of markers and print to the screen. ---*/ nMarker = mesh->GetNumberOfMarkers(); config->SetnMarker_All(nMarker); - if (rank == MASTER_NODE) - cout << nMarker << " surface markers." << endl; + if (rank == MASTER_NODE) cout << nMarker << " surface markers." << endl; /*--- Create the data structure for boundary elements. ---*/ - bound = new CPrimalGrid**[nMarker]; - nElem_Bound = new unsigned long [nMarker]; - Tag_to_Marker = new string [config->GetnMarker_Max()]; + bound = new CPrimalGrid**[nMarker]; + nElem_Bound = new unsigned long[nMarker]; + Tag_to_Marker = new string[config->GetnMarker_Max()]; /*--- Retrieve the name of the surface markers as well as the number of surface elements for every marker. ---*/ - const auto §ionNames = mesh->GetMarkerNames(); - const auto &nSurfElemPerMarker = mesh->GetNumberOfSurfaceElementsAllMarkers(); + const auto& sectionNames = mesh->GetMarkerNames(); + const auto& nSurfElemPerMarker = mesh->GetNumberOfSurfaceElementsAllMarkers(); /*--- Loop over all sections that we extracted from the grid file that were identified as boundary element sections so that we can store those elements into our SU2 data structures. ---*/ for (int iMarker = 0; iMarker < nMarker; ++iMarker) { - /*--- Get the string name and set the number of surface elements for this marker. ---*/ - string Marker_Tag = sectionNames[iMarker]; + string Marker_Tag = sectionNames[iMarker]; nElem_Bound[iMarker] = nSurfElemPerMarker[iMarker]; /*--- Allocate the memory of the pointers for the surface @@ -459,14 +449,13 @@ void CPhysicalGeometry::LoadLinearlyPartitionedSurfaceElementsFEM(CConfig *confi bound[iMarker] = new CPrimalGrid*[nElem_Bound[iMarker]]; /*--- Retrieve the boundary element data for this marker. ---*/ - const auto &dataElems = mesh->GetSurfaceElementConnectivityForMarker(iMarker); + const auto& dataElems = mesh->GetSurfaceElementConnectivityForMarker(iMarker); /*--- Loop over the number of boundary elements for this marker. ---*/ unsigned long ind = 0; - for (unsigned long jElem=0; jElemGetTimeLevel(); /*--- Determine the time level of Elem1, which is either owned or external. Hence a distinction must be made. ---*/ unsigned short timeLevel1; - if(elemPartitioner.GetRankContainingIndex(localFaces[i].elemID1) == static_cast(rank)) { + if (elemPartitioner.GetRankContainingIndex(localFaces[i].elemID1) == static_cast(rank)) { const unsigned long elemID1 = localFaces[i].elemID1 - elemPartitioner.GetFirstIndexOnRank(rank); timeLevel1 = elem[elemID1]->GetTimeLevel(); } else { @@ -974,7 +962,6 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { of the graph. First the faces. ---*/ vector > adjacency(nElem, vector(0)); for (unsigned long i = 0; i < nFacesLoc; ++i) { - /*--- Determine the local index of elem0, which is always stored locally, and add elemID1 to the adjacency list. ---*/ const unsigned long elem0 = localFaces[i].elemID0 - elemPartitioner.GetFirstIndexOnRank(rank); @@ -983,7 +970,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Check if this is not a periodic face and if the second element is also a local element. If so, add elemID0 to the adjacency list ---*/ if (localFaces[i].periodicIndex == 0) { - if(elemPartitioner.GetRankContainingIndex(localFaces[i].elemID1) == static_cast(rank)) { + if (elemPartitioner.GetRankContainingIndex(localFaces[i].elemID1) == static_cast(rank)) { const unsigned long elem1 = localFaces[i].elemID1 - elemPartitioner.GetFirstIndexOnRank(rank); adjacency[elem1].push_back(localFaces[i].elemID0); } @@ -1004,7 +991,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { are present. ParMETIS is not able to deal with self entries, hence they must be removed as well. */ for (unsigned long i = 0; i < nElem; ++i) { - const unsigned long globalElemID = i + + elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long globalElemID = i + +elemPartitioner.GetFirstIndexOnRank(rank); unsigned long nEntriesNew = adjacency[i].size(); for (unsigned long j = 0; j < adjacency[i].size(); ++j) { @@ -1045,7 +1032,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { sort(adjacency[elemID].begin(), adjacency[elemID].end()); /* Check if the donor element is stored locally. */ - if(elemPartitioner.GetRankContainingIndex(donors[i]) == static_cast(rank)) { + if (elemPartitioner.GetRankContainingIndex(donors[i]) == static_cast(rank)) { /* Donor is stored locally. Add the entry to the graph and sort it afterwards. */ const unsigned long localDonorID = donors[i] - elemPartitioner.GetFirstIndexOnRank(rank); @@ -1070,7 +1057,6 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { vector sendToRank(size, 0); for (unsigned long i = 0; i < additionalExternalEntriesGraph.size(); i += 2) { - /*--- Determine the rank where this external is stored and update the corresponding communication buffers accordingly. ---*/ const unsigned long rankElem = elemPartitioner.GetRankContainingIndex(additionalExternalEntriesGraph[i]); @@ -1162,8 +1148,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Determine the array, which stores the distribution of the graph nodes over the ranks. ---*/ vector vtxdist(size + 1); - for (int i = 0; i <= size; ++i) - vtxdist[i] = static_cast(elemPartitioner.GetCumulativeSizeBeforeRank(i)); + for (int i = 0; i <= size; ++i) vtxdist[i] = static_cast(elemPartitioner.GetCumulativeSizeBeforeRank(i)); /* Create the array xadjPar, which contains the number of edges for each vertex of the graph in ParMETIS format. */ @@ -1995,7 +1980,8 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig* config) { /* Easier storage of the element type, the corresponding volume element and the polynomial degree for the solution and grid. */ const unsigned short VTK_Type = bound[iMarker][l]->GetVTK_Type(); - const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long elemID = + bound[iMarker][l]->GetDomainElement() - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short nPolyGrid = bound[iMarker][l]->GetNPolyGrid(); const unsigned short nPolySol = elem[elemID]->GetNPolySol(); const unsigned short VTK_Elem = elem[elemID]->GetVTK_Type(); @@ -2426,7 +2412,6 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig* config) { void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector& localFaces, map& mapExternalElemIDToTimeLevel) { - /*--- Define the linear partitioning of the elements. ---*/ CLinearPartitioner elemPartitioner(Global_nElem, 0); @@ -2442,8 +2427,7 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector /*--- Check for external element. This is done by checking the local elements and if it is not found, it is an external. ---*/ const auto UMI = Global_to_Local_Elem.find(FI->elemID1); - if(UMI == Global_to_Local_Elem.end()) { - + if (UMI == Global_to_Local_Elem.end()) { /* This element is an external element. Store it in the map mapExternalElemIDToTimeLevel if not already done so. */ map::iterator MI; @@ -2471,12 +2455,10 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector const unsigned long* donors = bound[iMarker][l]->GetDonorsWallFunctions(); /*--- Loop over the number of donors for this boundary element. ---*/ - for(unsigned short i=0; ifirst); @@ -2711,8 +2692,7 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector SU2_MPI::Recv(sendElem[i].data(), sizeMess, MPI_UNSIGNED_LONG, sendRank[i], rank, SU2_MPI::GetComm(), &status); - for (int j = 0; j < sizeMess; ++j) - sendElem[i][j] -= elemPartitioner.GetFirstIndexOnRank(rank); + for (int j = 0; j < sizeMess; ++j) sendElem[i][j] -= elemPartitioner.GetFirstIndexOnRank(rank); } /* Complete the non-blocking sends. Synchronize the processors afterwards, @@ -2803,8 +2783,8 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector for (unsigned short iMarker = 0; iMarker < nMarker; ++iMarker) { for (unsigned long l = 0; l < nElem_Bound[iMarker]; ++l) { /* Determine the ID of the adjacent element. */ - const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - - elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long elemID = + bound[iMarker][l]->GetDomainElement() - elemPartitioner.GetFirstIndexOnRank(rank); /* Get the number of donor elements for the wall function treatment and the pointer to the array which stores this info. */ @@ -2813,14 +2793,11 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector /* Loop over the number of donors and check the time levels. */ for (unsigned short i = 0; i < nDonors; ++i) { - /* Determine the status of the donor element. */ - if(elemPartitioner.GetRankContainingIndex(donors[i]) == static_cast(rank)) { - + if (elemPartitioner.GetRankContainingIndex(donors[i]) == static_cast(rank)) { /* Donor is stored locally. Determine its local ID and get the time levels of both elements. */ - const unsigned long donorID = donors[i] - - elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long donorID = donors[i] - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short timeLevelB = elem[elemID]->GetTimeLevel(); const unsigned short timeLevelD = elem[donorID]->GetTimeLevel(); const unsigned short timeLevel = min(timeLevelB, timeLevelD); @@ -2871,12 +2848,11 @@ void CPhysicalGeometry::DetermineTimeLevelElements(CConfig* config, const vector if (FI->elemID1 < Global_nElem) { /* Local element ID of the first element. Per definition this is always a locally stored element. Also store its time level. */ - const unsigned long elemID0 = FI->elemID0 - - elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long elemID0 = FI->elemID0 - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short timeLevel0 = elem[elemID0]->GetTimeLevel(); /* Determine the status of the second element. */ - if(elemPartitioner.GetRankContainingIndex(FI->elemID1) == static_cast(rank)) { + if (elemPartitioner.GetRankContainingIndex(FI->elemID1) == static_cast(rank)) { /* Both elements are stored locally. Determine the local element of the second element and determine the minimum time level. */ @@ -3028,7 +3004,6 @@ void CPhysicalGeometry::ComputeFEMGraphWeights(CConfig* config, const vector >& adjacency, const map& mapExternalElemIDToTimeLevel, vector& vwgt, vector >& adjwgt) { - /*--- Define the linear partitioning of the elements. ---*/ CLinearPartitioner elemPartitioner(Global_nElem, 0); @@ -3212,8 +3187,8 @@ void CPhysicalGeometry::ComputeFEMGraphWeights(CConfig* config, const vectorGetVTK_Type(); - const unsigned long elemID = bound[iMarker][l]->GetDomainElement() - - elemPartitioner.GetFirstIndexOnRank(rank); + const unsigned long elemID = + bound[iMarker][l]->GetDomainElement() - elemPartitioner.GetFirstIndexOnRank(rank); const unsigned short nPolySol = elem[elemID]->GetNPolySol(); const unsigned short VTK_Type_Elem = elem[elemID]->GetVTK_Type(); const bool JacIsConstant = bound[iMarker][l]->GetJacobianConsideredConstant(); @@ -3294,7 +3269,7 @@ void CPhysicalGeometry::ComputeFEMGraphWeights(CConfig* config, const vector(rank)) { + if (elemPartitioner.GetRankContainingIndex(adjacency[i][j]) == static_cast(rank)) { /* Locally stored element. Determine its local ID and set the time level and number of solution DOFs. */ unsigned long elemID1 = adjacency[i][j] - elemPartitioner.GetFirstIndexOnRank(rank); diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index b97e6399df2..20c2b247510 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -3452,20 +3452,28 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena CMeshReaderBase* Mesh = nullptr; switch (val_format) { case SU2: - if (fem_solver) Mesh = new CSU2ASCIIMeshReaderFEM(config, val_iZone, val_nZone); - else Mesh = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) + Mesh = new CSU2ASCIIMeshReaderFEM(config, val_iZone, val_nZone); + else + Mesh = new CSU2ASCIIMeshReaderFVM(config, val_iZone, val_nZone); break; case CGNS_GRID: - if (fem_solver) Mesh = new CCGNSMeshReaderFEM(config, val_iZone, val_nZone); - else Mesh = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) + Mesh = new CCGNSMeshReaderFEM(config, val_iZone, val_nZone); + else + Mesh = new CCGNSMeshReaderFVM(config, val_iZone, val_nZone); break; case RECTANGLE: - if (fem_solver) Mesh = new CRectangularMeshReaderFEM(config, val_iZone, val_nZone); - else Mesh = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) + Mesh = new CRectangularMeshReaderFEM(config, val_iZone, val_nZone); + else + Mesh = new CRectangularMeshReaderFVM(config, val_iZone, val_nZone); break; case BOX: - if (fem_solver) Mesh = new CBoxMeshReaderFEM(config, val_iZone, val_nZone); - else Mesh = new CBoxMeshReaderFVM(config, val_iZone, val_nZone); + if (fem_solver) + Mesh = new CBoxMeshReaderFEM(config, val_iZone, val_nZone); + else + Mesh = new CBoxMeshReaderFVM(config, val_iZone, val_nZone); break; default: SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION); @@ -3507,17 +3515,14 @@ void CPhysicalGeometry::Read_Mesh(CConfig* config, const string& val_mesh_filena /*--- Make a distinction between the FVM solver and FEM solver how to load the grid data in the member variables of CPhysicalGeometry. ---*/ - if( fem_solver ) { - + if (fem_solver) { /*--- Load the grid points, volume elements, and surface elements from the mesh object into the proper SU2 data structures. ---*/ LoadLinearlyPartitionedPointsFEM(config, Mesh); LoadLinearlyPartitionedVolumeElementsFEM(config, Mesh); LoadLinearlyPartitionedSurfaceElementsFEM(config, Mesh); - } - else { - + } else { /*--- Load the grid points, volume elements, and surface elements from the mesh object into the proper SU2 data structures. ---*/ diff --git a/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp index 56551341517..44dfde1dc7f 100644 --- a/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CBoxMeshReaderFEM.cpp @@ -29,15 +29,13 @@ #include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CBoxMeshReaderFEM.hpp" -CBoxMeshReaderFEM::CBoxMeshReaderFEM(const CConfig *val_config, unsigned short val_iZone, - unsigned short val_nZone) +CBoxMeshReaderFEM::CBoxMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : CMeshReaderBase(val_config, val_iZone, val_nZone) { - /* The box mesh is always 3D. */ dimension = 3; /* Set the VTK type for the interior elements and the boundary elements. */ - KindElem = HEXAHEDRON; + KindElem = HEXAHEDRON; KindBound = QUADRILATERAL; /* The number of grid nodes in the i, j and k directions. */ @@ -68,24 +66,22 @@ CBoxMeshReaderFEM::CBoxMeshReaderFEM(const CConfig *val_config, unsigned short v CBoxMeshReaderFEM::~CBoxMeshReaderFEM() = default; void CBoxMeshReaderFEM::ComputeBoxPointCoordinates() { - /*--- Set the global count of points based on the grid dimensions. ---*/ - numberOfGlobalPoints = nNode*mNode*pNode; + numberOfGlobalPoints = nNode * mNode * pNode; /*--- Loop over the local elements to determine the global point IDs to be stored on this rank. --*/ unsigned long ind = 0; - for(unsigned long i=0; i(rank)) { - + const unsigned long globalElemID = kNode * nElemIJ + jNode * nElemI; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[0].push_back(KindBound); // VTK type. @@ -201,10 +190,10 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { surfaceElementConnectivity[0].push_back(ind); // Global surface element ID. surfaceElementConnectivity[0].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[0].push_back(kNode*mNode*nNode + jNode*nNode); - surfaceElementConnectivity[0].push_back((kNode+1)*mNode*nNode + jNode*nNode); - surfaceElementConnectivity[0].push_back(kNode*mNode*nNode + (jNode+1)*nNode); - surfaceElementConnectivity[0].push_back((kNode+1)*mNode*nNode + (jNode+1)*nNode); + surfaceElementConnectivity[0].push_back(kNode * mNode * nNode + jNode * nNode); + surfaceElementConnectivity[0].push_back((kNode + 1) * mNode * nNode + jNode * nNode); + surfaceElementConnectivity[0].push_back(kNode * mNode * nNode + (jNode + 1) * nNode); + surfaceElementConnectivity[0].push_back((kNode + 1) * mNode * nNode + (jNode + 1) * nNode); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[0]; @@ -216,14 +205,12 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { markerNames[1] = "x_plus"; ind = 0; - for(unsigned long kNode = 0; kNode < pNode-1; ++kNode) { - for(unsigned long jNode = 0; jNode < mNode-1; ++jNode, ++ind) { - + for (unsigned long kNode = 0; kNode < pNode - 1; ++kNode) { + for (unsigned long jNode = 0; jNode < mNode - 1; ++jNode, ++ind) { /*--- Determine the corresponding global element ID and check if it is stored on this rank. ---*/ - const unsigned long globalElemID = kNode*nElemIJ + jNode*nElemI + nElemI-1; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + const unsigned long globalElemID = kNode * nElemIJ + jNode * nElemI + nElemI - 1; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[1].push_back(KindBound); // VTK type. @@ -232,10 +219,10 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { surfaceElementConnectivity[1].push_back(ind); // Global surface element ID. surfaceElementConnectivity[1].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[1].push_back(kNode*mNode*nNode + jNode*nNode + (nNode-1)); - surfaceElementConnectivity[1].push_back(kNode*mNode*nNode + (jNode+1)*nNode + (nNode-1)); - surfaceElementConnectivity[1].push_back((kNode+1)*mNode*nNode + jNode*nNode + (nNode-1)); - surfaceElementConnectivity[1].push_back((kNode+1)*mNode*nNode + (jNode+1)*nNode + (nNode-1)); + surfaceElementConnectivity[1].push_back(kNode * mNode * nNode + jNode * nNode + (nNode - 1)); + surfaceElementConnectivity[1].push_back(kNode * mNode * nNode + (jNode + 1) * nNode + (nNode - 1)); + surfaceElementConnectivity[1].push_back((kNode + 1) * mNode * nNode + jNode * nNode + (nNode - 1)); + surfaceElementConnectivity[1].push_back((kNode + 1) * mNode * nNode + (jNode + 1) * nNode + (nNode - 1)); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[1]; @@ -247,14 +234,12 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { markerNames[2] = "y_minus"; ind = 0; - for (unsigned long kNode = 0; kNode < pNode-1; ++kNode) { - for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { - - /*--- Determine the corresponding global element ID and check - if it is stored on this rank. ---*/ - const unsigned long globalElemID = kNode*nElemIJ + iNode; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + for (unsigned long kNode = 0; kNode < pNode - 1; ++kNode) { + for (unsigned long iNode = 0; iNode < nNode - 1; ++iNode, ++ind) { + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = kNode * nElemIJ + iNode; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[2].push_back(KindBound); // VTK type. @@ -263,10 +248,10 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { surfaceElementConnectivity[2].push_back(ind); // Global surface element ID. surfaceElementConnectivity[2].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[2].push_back(kNode*mNode*nNode + iNode); - surfaceElementConnectivity[2].push_back(kNode*mNode*nNode + iNode+1); - surfaceElementConnectivity[2].push_back((kNode+1)*mNode*nNode + iNode); - surfaceElementConnectivity[2].push_back((kNode+1)*mNode*nNode + iNode+1); + surfaceElementConnectivity[2].push_back(kNode * mNode * nNode + iNode); + surfaceElementConnectivity[2].push_back(kNode * mNode * nNode + iNode + 1); + surfaceElementConnectivity[2].push_back((kNode + 1) * mNode * nNode + iNode); + surfaceElementConnectivity[2].push_back((kNode + 1) * mNode * nNode + iNode + 1); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[2]; @@ -278,14 +263,12 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { markerNames[3] = "y_plus"; ind = 0; - for (unsigned long kNode = 0; kNode < pNode-1; ++kNode) { - for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { - - /*--- Determine the corresponding global element ID and check - if it is stored on this rank. ---*/ - const unsigned long globalElemID = kNode*nElemIJ + (mNode-2)*nElemI + iNode; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + for (unsigned long kNode = 0; kNode < pNode - 1; ++kNode) { + for (unsigned long iNode = 0; iNode < nNode - 1; ++iNode, ++ind) { + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = kNode * nElemIJ + (mNode - 2) * nElemI + iNode; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[3].push_back(KindBound); // VTK type. @@ -294,10 +277,10 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { surfaceElementConnectivity[3].push_back(ind); // Global surface element ID. surfaceElementConnectivity[3].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[3].push_back(kNode*mNode*nNode + (mNode-1)*nNode + iNode); - surfaceElementConnectivity[3].push_back(kNode*mNode*nNode + (mNode-1)*nNode + iNode+1); - surfaceElementConnectivity[3].push_back((kNode+1)*mNode*nNode + (mNode-1)*nNode + iNode); - surfaceElementConnectivity[3].push_back((kNode+1)*mNode*nNode + (mNode-1)*nNode + iNode+1); + surfaceElementConnectivity[3].push_back(kNode * mNode * nNode + (mNode - 1) * nNode + iNode); + surfaceElementConnectivity[3].push_back(kNode * mNode * nNode + (mNode - 1) * nNode + iNode + 1); + surfaceElementConnectivity[3].push_back((kNode + 1) * mNode * nNode + (mNode - 1) * nNode + iNode); + surfaceElementConnectivity[3].push_back((kNode + 1) * mNode * nNode + (mNode - 1) * nNode + iNode + 1); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[3]; @@ -309,14 +292,12 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { markerNames[4] = "z_minus"; ind = 0; - for (unsigned long jNode = 0; jNode < mNode-1; ++jNode) { - for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { - - /*--- Determine the corresponding global element ID and check - if it is stored on this rank. ---*/ - const unsigned long globalElemID = jNode*nElemI + iNode; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + for (unsigned long jNode = 0; jNode < mNode - 1; ++jNode) { + for (unsigned long iNode = 0; iNode < nNode - 1; ++iNode, ++ind) { + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = jNode * nElemI + iNode; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[4].push_back(KindBound); // VTK type. @@ -325,10 +306,10 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { surfaceElementConnectivity[4].push_back(ind); // Global surface element ID. surfaceElementConnectivity[4].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[4].push_back(jNode*nNode + iNode); - surfaceElementConnectivity[4].push_back(jNode*nNode + iNode+1); - surfaceElementConnectivity[4].push_back((jNode+1)*nNode + iNode); - surfaceElementConnectivity[4].push_back((jNode+1)*nNode + iNode+1); + surfaceElementConnectivity[4].push_back(jNode * nNode + iNode); + surfaceElementConnectivity[4].push_back(jNode * nNode + iNode + 1); + surfaceElementConnectivity[4].push_back((jNode + 1) * nNode + iNode); + surfaceElementConnectivity[4].push_back((jNode + 1) * nNode + iNode + 1); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[4]; @@ -340,14 +321,12 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { markerNames[5] = "z_plus"; ind = 0; - for (unsigned long jNode = 0; jNode < mNode-1; ++jNode) { - for (unsigned long iNode = 0; iNode < nNode-1; ++iNode, ++ind) { - - /*--- Determine the corresponding global element ID and check - if it is stored on this rank. ---*/ - const unsigned long globalElemID = (pNode-2)*nElemIJ + jNode*nElemI + iNode; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + for (unsigned long jNode = 0; jNode < mNode - 1; ++jNode) { + for (unsigned long iNode = 0; iNode < nNode - 1; ++iNode, ++ind) { + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = (pNode - 2) * nElemIJ + jNode * nElemI + iNode; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[5].push_back(KindBound); // VTK type. @@ -356,10 +335,10 @@ void CBoxMeshReaderFEM::ComputeBoxSurfaceConnectivity() { surfaceElementConnectivity[5].push_back(ind); // Global surface element ID. surfaceElementConnectivity[5].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + jNode*nNode + iNode); - surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + jNode*nNode + iNode+1); - surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + (jNode+1)*nNode + iNode); - surfaceElementConnectivity[5].push_back((pNode-1)*mNode*nNode + (jNode+1)*nNode + iNode+1); + surfaceElementConnectivity[5].push_back((pNode - 1) * mNode * nNode + jNode * nNode + iNode); + surfaceElementConnectivity[5].push_back((pNode - 1) * mNode * nNode + jNode * nNode + iNode + 1); + surfaceElementConnectivity[5].push_back((pNode - 1) * mNode * nNode + (jNode + 1) * nNode + iNode); + surfaceElementConnectivity[5].push_back((pNode - 1) * mNode * nNode + (jNode + 1) * nNode + iNode + 1); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[5]; diff --git a/Common/src/geometry/meshreader/CCGNSElementType.cpp b/Common/src/geometry/meshreader/CCGNSElementType.cpp index 8ed50fb91df..53a549c8c78 100644 --- a/Common/src/geometry/meshreader/CCGNSElementType.cpp +++ b/Common/src/geometry/meshreader/CCGNSElementType.cpp @@ -35,58 +35,111 @@ using namespace std; -void CCGNSElementType::CGNSToSU2(const ElementType_t val_elemType, - const unsigned long val_globalID, - const cgsize_t *connCGNS, - std::vector &connSU2) { - +void CCGNSElementType::CGNSToSU2(const ElementType_t val_elemType, const unsigned long val_globalID, + const cgsize_t* connCGNS, std::vector& connSU2) { /*--- Clear the contents of connSU2. ---*/ connSU2.clear(); /*--- Search in the stored elements if the current element type is present. ---*/ unsigned long ind; - for(ind=0; ind SU2ToCGNS; - switch( val_elemType ) { - - case NODE: CreateDataNODE (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case BAR_2: CreateDataBAR_2 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case BAR_3: CreateDataBAR_3 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case BAR_4: CreateDataBAR_4 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case BAR_5: CreateDataBAR_5 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TRI_3: CreateDataTRI_3 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TRI_6: CreateDataTRI_6 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TRI_10: CreateDataTRI_10 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TRI_15: CreateDataTRI_15 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case QUAD_4: CreateDataQUAD_4 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case QUAD_9: CreateDataQUAD_9 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case QUAD_16: CreateDataQUAD_16 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case QUAD_25: CreateDataQUAD_25 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TETRA_4: CreateDataTETRA_4 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TETRA_10: CreateDataTETRA_10(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TETRA_20: CreateDataTETRA_20(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case TETRA_35: CreateDataTETRA_35(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PYRA_5: CreateDataPYRA_5 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PYRA_14: CreateDataPYRA_14 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PYRA_30: CreateDataPYRA_30 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PYRA_55: CreateDataPYRA_55 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PENTA_6: CreateDataPENTA_6 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PENTA_18: CreateDataPENTA_18(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PENTA_40: CreateDataPENTA_40(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case PENTA_75: CreateDataPENTA_75(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case HEXA_8: CreateDataHEXA_8 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case HEXA_27: CreateDataHEXA_27 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case HEXA_64: CreateDataHEXA_64 (VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; - case HEXA_125: CreateDataHEXA_125(VTK_Type, nPoly, nDOFs, SU2ToCGNS); break; + switch (val_elemType) { + case NODE: + CreateDataNODE(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case BAR_2: + CreateDataBAR_2(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case BAR_3: + CreateDataBAR_3(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case BAR_4: + CreateDataBAR_4(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case BAR_5: + CreateDataBAR_5(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TRI_3: + CreateDataTRI_3(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TRI_6: + CreateDataTRI_6(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TRI_10: + CreateDataTRI_10(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TRI_15: + CreateDataTRI_15(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case QUAD_4: + CreateDataQUAD_4(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case QUAD_9: + CreateDataQUAD_9(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case QUAD_16: + CreateDataQUAD_16(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case QUAD_25: + CreateDataQUAD_25(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TETRA_4: + CreateDataTETRA_4(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TETRA_10: + CreateDataTETRA_10(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TETRA_20: + CreateDataTETRA_20(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case TETRA_35: + CreateDataTETRA_35(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PYRA_5: + CreateDataPYRA_5(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PYRA_14: + CreateDataPYRA_14(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PYRA_30: + CreateDataPYRA_30(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PYRA_55: + CreateDataPYRA_55(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PENTA_6: + CreateDataPENTA_6(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PENTA_18: + CreateDataPENTA_18(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PENTA_40: + CreateDataPENTA_40(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case PENTA_75: + CreateDataPENTA_75(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case HEXA_8: + CreateDataHEXA_8(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case HEXA_27: + CreateDataHEXA_27(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case HEXA_64: + CreateDataHEXA_64(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; + case HEXA_125: + CreateDataHEXA_125(VTK_Type, nPoly, nDOFs, SU2ToCGNS); + break; default: ostringstream message; @@ -103,7 +156,7 @@ void CCGNSElementType::CGNSToSU2(const ElementType_t val_elemType, } /*--- Allocate the memory for connSU2 and store the meta data. ---*/ - connSU2.resize(nDOFsStored[ind]+5); + connSU2.resize(nDOFsStored[ind] + 5); connSU2[0] = VTKTypeStored[ind]; connSU2[1] = nPolyStored[ind]; @@ -114,8 +167,7 @@ void CCGNSElementType::CGNSToSU2(const ElementType_t val_elemType, /*--- Loop over the DOFs and convert the connectivity from CGNS to SU2 format. Keep in mind that CGNS start the numbering at 1 while SU2 starts at 0. ---*/ - for(unsigned short i=0; i &SU2ToCGNS) { - +void CCGNSElementType::CreateDataNODE(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* Set the required data for a NODE. */ VTK_Type = VERTEX; - nPoly = 0; - nDOFs = 1; + nPoly = 0; + nDOFs = 1; SU2ToCGNS.push_back(0); } -void CCGNSElementType::CreateDataBAR_2(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataBAR_2(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The BAR_2 element is a linear element. The numbering of the nodes is the same for CGNS and SU2. */ VTK_Type = LINE; - nPoly = 1; - nDOFs = 2; + nPoly = 1; + nDOFs = 2; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; } -void CCGNSElementType::CreateDataBAR_3(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataBAR_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The BAR_3 element is a quadratic element. SU2 numbers to nodes with increasing parametric value, while in CGNS the internal node is numbered last. */ VTK_Type = LINE; - nPoly = 2; - nDOFs = 3; + nPoly = 2; + nDOFs = 3; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 2; SU2ToCGNS[2] = 1; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 2; + SU2ToCGNS[2] = 1; } -void CCGNSElementType::CreateDataBAR_4(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataBAR_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The BAR_4 element is a cubic element. SU2 numbers to nodes with increasing parametric value, while in CGNS the internal nodes are numbered last. */ VTK_Type = LINE; - nPoly = 3; - nDOFs = 4; + nPoly = 3; + nDOFs = 4; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 2; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 1; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 2; + SU2ToCGNS[2] = 3; + SU2ToCGNS[3] = 1; } -void CCGNSElementType::CreateDataBAR_5(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataBAR_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The BAR_5 element is a quartic element. SU2 numbers to nodes with increasing parametric value, while in CGNS the internal nodes are numbered last. */ VTK_Type = LINE; - nPoly = 4; - nDOFs = 5; + nPoly = 4; + nDOFs = 5; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 2; SU2ToCGNS[2] = 3; - SU2ToCGNS[3] = 4; SU2ToCGNS[4] = 1; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 2; + SU2ToCGNS[2] = 3; + SU2ToCGNS[3] = 4; + SU2ToCGNS[4] = 1; } -void CCGNSElementType::CreateDataTRI_3(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTRI_3(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TRI_3 element is a linear triangle. The node numbering is the same in SU2 and CGNS. */ VTK_Type = TRIANGLE; - nPoly = 1; - nDOFs = 3; + nPoly = 1; + nDOFs = 3; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; + SU2ToCGNS[2] = 2; } -void CCGNSElementType::CreateDataTRI_6(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTRI_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TRI_6 element is a quadratic triangle. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -227,19 +269,20 @@ void CCGNSElementType::CreateDataTRI_6(unsigned short &VTK_Type, where the i-direction is defined from node 0 to 1 and the j-direction from node 0 along the other edge. */ VTK_Type = TRIANGLE; - nPoly = 2; - nDOFs = 6; + nPoly = 2; + nDOFs = 6; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 3; SU2ToCGNS[2] = 1; - SU2ToCGNS[3] = 5; SU2ToCGNS[4] = 4; SU2ToCGNS[5] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 3; + SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 5; + SU2ToCGNS[4] = 4; + SU2ToCGNS[5] = 2; } -void CCGNSElementType::CreateDataTRI_10(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTRI_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TRI_10 element is a cubic triangle. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -248,20 +291,24 @@ void CCGNSElementType::CreateDataTRI_10(unsigned short &VTK_Type, where the i-direction is defined from node 0 to 1 and the j-direction from node 0 along the other edge. */ VTK_Type = TRIANGLE; - nPoly = 3; - nDOFs = 10; + nPoly = 3; + nDOFs = 10; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 3; SU2ToCGNS[2] = 4; SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 8; SU2ToCGNS[5] = 9; SU2ToCGNS[6] = 5; SU2ToCGNS[7] = 7; - SU2ToCGNS[8] = 6; SU2ToCGNS[9] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 3; + SU2ToCGNS[2] = 4; + SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 8; + SU2ToCGNS[5] = 9; + SU2ToCGNS[6] = 5; + SU2ToCGNS[7] = 7; + SU2ToCGNS[8] = 6; + SU2ToCGNS[9] = 2; } -void CCGNSElementType::CreateDataTRI_15(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTRI_15(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TRI_15 element is a quartic triangle. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -273,21 +320,29 @@ void CCGNSElementType::CreateDataTRI_15(unsigned short &VTK_Type, the location for uniform spacing. This effect is currently ignored, i.e. it is assumed that the spacing in parameter space is uniform. */ VTK_Type = TRIANGLE; - nPoly = 4; - nDOFs = 15; + nPoly = 4; + nDOFs = 15; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 3; SU2ToCGNS[2] = 4; SU2ToCGNS[3] = 5; - SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 11; SU2ToCGNS[6] = 12; SU2ToCGNS[7] = 13; - SU2ToCGNS[8] = 6; SU2ToCGNS[9] = 10; SU2ToCGNS[10] = 14; SU2ToCGNS[11] = 7; - SU2ToCGNS[12] = 9; SU2ToCGNS[13] = 8; SU2ToCGNS[14] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 3; + SU2ToCGNS[2] = 4; + SU2ToCGNS[3] = 5; + SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 11; + SU2ToCGNS[6] = 12; + SU2ToCGNS[7] = 13; + SU2ToCGNS[8] = 6; + SU2ToCGNS[9] = 10; + SU2ToCGNS[10] = 14; + SU2ToCGNS[11] = 7; + SU2ToCGNS[12] = 9; + SU2ToCGNS[13] = 8; + SU2ToCGNS[14] = 2; } -void CCGNSElementType::CreateDataQUAD_4(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataQUAD_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The QUAD_4 element is a linear quadrilateral. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes (not present for QUAD_4). @@ -296,18 +351,18 @@ void CCGNSElementType::CreateDataQUAD_4(unsigned short &VTK_Type, where the i-direction is defined from node 0 to 1 and the j-direction from node 0 along the other edge. */ VTK_Type = QUADRILATERAL; - nPoly = 1; - nDOFs = 4; + nPoly = 1; + nDOFs = 4; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; + SU2ToCGNS[2] = 3; + SU2ToCGNS[3] = 2; } -void CCGNSElementType::CreateDataQUAD_9(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataQUAD_9(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The QUAD_9 element is a quadratic quadrilateral. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -316,20 +371,23 @@ void CCGNSElementType::CreateDataQUAD_9(unsigned short &VTK_Type, where the i-direction is defined from node 0 to 1 and the j-direction from node 0 along the other edge. */ VTK_Type = QUADRILATERAL; - nPoly = 2; - nDOFs = 9; + nPoly = 2; + nDOFs = 9; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 7; - SU2ToCGNS[4] = 8; SU2ToCGNS[5] = 5; SU2ToCGNS[6] = 3; SU2ToCGNS[7] = 6; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 4; + SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 7; + SU2ToCGNS[4] = 8; + SU2ToCGNS[5] = 5; + SU2ToCGNS[6] = 3; + SU2ToCGNS[7] = 6; SU2ToCGNS[8] = 2; } -void CCGNSElementType::CreateDataQUAD_16(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataQUAD_16(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The QUAD_16 element is a cubic quadrilateral. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -338,21 +396,30 @@ void CCGNSElementType::CreateDataQUAD_16(unsigned short &VTK_Type, where the i-direction is defined from node 0 to 1 and the j-direction from node 0 along the other edge. */ VTK_Type = QUADRILATERAL; - nPoly = 3; - nDOFs = 16; + nPoly = 3; + nDOFs = 16; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 11; SU2ToCGNS[5] = 12; SU2ToCGNS[6] = 13; SU2ToCGNS[7] = 6; - SU2ToCGNS[8] = 10; SU2ToCGNS[9] = 15; SU2ToCGNS[10] = 14; SU2ToCGNS[11] = 7; - SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 9; SU2ToCGNS[14] = 8; SU2ToCGNS[15] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 4; + SU2ToCGNS[2] = 5; + SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 11; + SU2ToCGNS[5] = 12; + SU2ToCGNS[6] = 13; + SU2ToCGNS[7] = 6; + SU2ToCGNS[8] = 10; + SU2ToCGNS[9] = 15; + SU2ToCGNS[10] = 14; + SU2ToCGNS[11] = 7; + SU2ToCGNS[12] = 3; + SU2ToCGNS[13] = 9; + SU2ToCGNS[14] = 8; + SU2ToCGNS[15] = 2; } -void CCGNSElementType::CreateDataQUAD_25(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataQUAD_25(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The QUAD_25 element is a quartic quadrilateral. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -361,39 +428,54 @@ void CCGNSElementType::CreateDataQUAD_25(unsigned short &VTK_Type, where the i-direction is defined from node 0 to 1 and the j-direction from node 0 along the other edge. */ VTK_Type = QUADRILATERAL; - nPoly = 4; - nDOFs = 25; + nPoly = 4; + nDOFs = 25; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 6; - SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 15; SU2ToCGNS[6] = 16; SU2ToCGNS[7] = 17; - SU2ToCGNS[8] = 18; SU2ToCGNS[9] = 7; SU2ToCGNS[10] = 14; SU2ToCGNS[11] = 23; - SU2ToCGNS[12] = 24; SU2ToCGNS[13] = 19; SU2ToCGNS[14] = 8; SU2ToCGNS[15] = 13; - SU2ToCGNS[16] = 22; SU2ToCGNS[17] = 21; SU2ToCGNS[18] = 20; SU2ToCGNS[19] = 9; - SU2ToCGNS[20] = 3; SU2ToCGNS[21] = 12; SU2ToCGNS[22] = 11; SU2ToCGNS[23] = 10; - SU2ToCGNS[24] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 4; + SU2ToCGNS[2] = 5; + SU2ToCGNS[3] = 6; + SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 15; + SU2ToCGNS[6] = 16; + SU2ToCGNS[7] = 17; + SU2ToCGNS[8] = 18; + SU2ToCGNS[9] = 7; + SU2ToCGNS[10] = 14; + SU2ToCGNS[11] = 23; + SU2ToCGNS[12] = 24; + SU2ToCGNS[13] = 19; + SU2ToCGNS[14] = 8; + SU2ToCGNS[15] = 13; + SU2ToCGNS[16] = 22; + SU2ToCGNS[17] = 21; + SU2ToCGNS[18] = 20; + SU2ToCGNS[19] = 9; + SU2ToCGNS[20] = 3; + SU2ToCGNS[21] = 12; + SU2ToCGNS[22] = 11; + SU2ToCGNS[23] = 10; + SU2ToCGNS[24] = 2; } -void CCGNSElementType::CreateDataTETRA_4(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTETRA_4(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TETRA_4 element is a linear tetrahedron. The node numbering is the same in SU2 and CGNS. */ VTK_Type = TETRAHEDRON; - nPoly = 1; - nDOFs = 4; + nPoly = 1; + nDOFs = 4; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 2; SU2ToCGNS[3] = 3; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; + SU2ToCGNS[2] = 2; + SU2ToCGNS[3] = 3; } -void CCGNSElementType::CreateDataTETRA_10(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTETRA_10(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TETRA_10 element is a quadratic tetrahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -404,20 +486,24 @@ void CCGNSElementType::CreateDataTETRA_10(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = TETRAHEDRON; - nPoly = 2; - nDOFs = 10; + nPoly = 2; + nDOFs = 10; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 6; - SU2ToCGNS[4] = 5; SU2ToCGNS[5] = 2; SU2ToCGNS[6] = 7; SU2ToCGNS[7] = 8; - SU2ToCGNS[8] = 9; SU2ToCGNS[9] = 3; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 4; + SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 6; + SU2ToCGNS[4] = 5; + SU2ToCGNS[5] = 2; + SU2ToCGNS[6] = 7; + SU2ToCGNS[7] = 8; + SU2ToCGNS[8] = 9; + SU2ToCGNS[9] = 3; } -void CCGNSElementType::CreateDataTETRA_20(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTETRA_20(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TETRA_20 element is a cubic tetrahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -428,22 +514,34 @@ void CCGNSElementType::CreateDataTETRA_20(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = TETRAHEDRON; - nPoly = 3; - nDOFs = 20; + nPoly = 3; + nDOFs = 20; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 9; SU2ToCGNS[5] = 16; SU2ToCGNS[6] = 6; SU2ToCGNS[7] = 8; - SU2ToCGNS[8] = 7; SU2ToCGNS[9] = 2; SU2ToCGNS[10] = 10; SU2ToCGNS[11] = 17; - SU2ToCGNS[12] = 12; SU2ToCGNS[13] = 19; SU2ToCGNS[14] = 18; SU2ToCGNS[15] = 14; - SU2ToCGNS[16] = 11; SU2ToCGNS[17] = 13; SU2ToCGNS[18] = 15; SU2ToCGNS[19] = 3; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 4; + SU2ToCGNS[2] = 5; + SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 9; + SU2ToCGNS[5] = 16; + SU2ToCGNS[6] = 6; + SU2ToCGNS[7] = 8; + SU2ToCGNS[8] = 7; + SU2ToCGNS[9] = 2; + SU2ToCGNS[10] = 10; + SU2ToCGNS[11] = 17; + SU2ToCGNS[12] = 12; + SU2ToCGNS[13] = 19; + SU2ToCGNS[14] = 18; + SU2ToCGNS[15] = 14; + SU2ToCGNS[16] = 11; + SU2ToCGNS[17] = 13; + SU2ToCGNS[18] = 15; + SU2ToCGNS[19] = 3; } -void CCGNSElementType::CreateDataTETRA_35(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataTETRA_35(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The TETRA_35 element is a quartic tetrahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -457,26 +555,49 @@ void CCGNSElementType::CreateDataTETRA_35(unsigned short &VTK_Type, currently ignored, i.e. it is assumed that the spacing in parameter space is uniform. */ VTK_Type = TETRAHEDRON; - nPoly = 4; - nDOFs = 35; + nPoly = 4; + nDOFs = 35; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 4; SU2ToCGNS[2] = 5; SU2ToCGNS[3] = 6; - SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 12; SU2ToCGNS[6] = 22; SU2ToCGNS[7] = 23; - SU2ToCGNS[8] = 7; SU2ToCGNS[9] = 11; SU2ToCGNS[10] = 24; SU2ToCGNS[11] = 8; - SU2ToCGNS[12] = 10; SU2ToCGNS[13] = 9; SU2ToCGNS[14] = 2; SU2ToCGNS[15] = 13; - SU2ToCGNS[16] = 25; SU2ToCGNS[17] = 26; SU2ToCGNS[18] = 16; SU2ToCGNS[19] = 32; - SU2ToCGNS[20] = 34; SU2ToCGNS[21] = 28; SU2ToCGNS[22] = 31; SU2ToCGNS[23] = 29; - SU2ToCGNS[24] = 19; SU2ToCGNS[25] = 14; SU2ToCGNS[26] = 27; SU2ToCGNS[27] = 17; - SU2ToCGNS[28] = 33; SU2ToCGNS[29] = 30; SU2ToCGNS[30] = 20; SU2ToCGNS[31] = 15; - SU2ToCGNS[32] = 18; SU2ToCGNS[33] = 21; SU2ToCGNS[34] = 3; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 4; + SU2ToCGNS[2] = 5; + SU2ToCGNS[3] = 6; + SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 12; + SU2ToCGNS[6] = 22; + SU2ToCGNS[7] = 23; + SU2ToCGNS[8] = 7; + SU2ToCGNS[9] = 11; + SU2ToCGNS[10] = 24; + SU2ToCGNS[11] = 8; + SU2ToCGNS[12] = 10; + SU2ToCGNS[13] = 9; + SU2ToCGNS[14] = 2; + SU2ToCGNS[15] = 13; + SU2ToCGNS[16] = 25; + SU2ToCGNS[17] = 26; + SU2ToCGNS[18] = 16; + SU2ToCGNS[19] = 32; + SU2ToCGNS[20] = 34; + SU2ToCGNS[21] = 28; + SU2ToCGNS[22] = 31; + SU2ToCGNS[23] = 29; + SU2ToCGNS[24] = 19; + SU2ToCGNS[25] = 14; + SU2ToCGNS[26] = 27; + SU2ToCGNS[27] = 17; + SU2ToCGNS[28] = 33; + SU2ToCGNS[29] = 30; + SU2ToCGNS[30] = 20; + SU2ToCGNS[31] = 15; + SU2ToCGNS[32] = 18; + SU2ToCGNS[33] = 21; + SU2ToCGNS[34] = 3; } -void CCGNSElementType::CreateDataPYRA_5(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPYRA_5(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PYRA_5 element is a linear pyramid. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes (not present in PYRA_5). @@ -487,19 +608,19 @@ void CCGNSElementType::CreateDataPYRA_5(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = PYRAMID; - nPoly = 1; - nDOFs = 5; + nPoly = 1; + nDOFs = 5; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 2; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; + SU2ToCGNS[2] = 3; + SU2ToCGNS[3] = 2; SU2ToCGNS[4] = 4; } -void CCGNSElementType::CreateDataPYRA_14(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPYRA_14(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PYRA_14 element is a quadratic pyramid. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -510,21 +631,28 @@ void CCGNSElementType::CreateDataPYRA_14(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = PYRAMID; - nPoly = 2; - nDOFs = 14; + nPoly = 2; + nDOFs = 14; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 5; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 8; - SU2ToCGNS[4] = 13; SU2ToCGNS[5] = 6; SU2ToCGNS[6] = 3; SU2ToCGNS[7] = 7; - SU2ToCGNS[8] = 2; SU2ToCGNS[9] = 9; SU2ToCGNS[10] = 10; SU2ToCGNS[11] = 12; - SU2ToCGNS[12] = 11; SU2ToCGNS[13] = 4; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 5; + SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 8; + SU2ToCGNS[4] = 13; + SU2ToCGNS[5] = 6; + SU2ToCGNS[6] = 3; + SU2ToCGNS[7] = 7; + SU2ToCGNS[8] = 2; + SU2ToCGNS[9] = 9; + SU2ToCGNS[10] = 10; + SU2ToCGNS[11] = 12; + SU2ToCGNS[12] = 11; + SU2ToCGNS[13] = 4; } -void CCGNSElementType::CreateDataPYRA_30(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPYRA_30(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PYRA_30 element is a cubic pyramid. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -535,25 +663,44 @@ void CCGNSElementType::CreateDataPYRA_30(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = PYRAMID; - nPoly = 3; - nDOFs = 30; + nPoly = 3; + nDOFs = 30; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 5; SU2ToCGNS[2] = 6; SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 12; SU2ToCGNS[5] = 21; SU2ToCGNS[6] = 22; SU2ToCGNS[7] = 7; - SU2ToCGNS[8] = 11; SU2ToCGNS[9] = 24; SU2ToCGNS[10] = 23; SU2ToCGNS[11] = 8; - SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 10; SU2ToCGNS[14] = 9; SU2ToCGNS[15] = 2; - SU2ToCGNS[16] = 13; SU2ToCGNS[17] = 25; SU2ToCGNS[18] = 15; SU2ToCGNS[19] = 28; - SU2ToCGNS[20] = 29; SU2ToCGNS[21] = 26; SU2ToCGNS[22] = 19; SU2ToCGNS[23] = 27; - SU2ToCGNS[24] = 17; SU2ToCGNS[25] = 14; SU2ToCGNS[26] = 16; SU2ToCGNS[27] = 20; - SU2ToCGNS[28] = 18; SU2ToCGNS[29] = 4; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 5; + SU2ToCGNS[2] = 6; + SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 12; + SU2ToCGNS[5] = 21; + SU2ToCGNS[6] = 22; + SU2ToCGNS[7] = 7; + SU2ToCGNS[8] = 11; + SU2ToCGNS[9] = 24; + SU2ToCGNS[10] = 23; + SU2ToCGNS[11] = 8; + SU2ToCGNS[12] = 3; + SU2ToCGNS[13] = 10; + SU2ToCGNS[14] = 9; + SU2ToCGNS[15] = 2; + SU2ToCGNS[16] = 13; + SU2ToCGNS[17] = 25; + SU2ToCGNS[18] = 15; + SU2ToCGNS[19] = 28; + SU2ToCGNS[20] = 29; + SU2ToCGNS[21] = 26; + SU2ToCGNS[22] = 19; + SU2ToCGNS[23] = 27; + SU2ToCGNS[24] = 17; + SU2ToCGNS[25] = 14; + SU2ToCGNS[26] = 16; + SU2ToCGNS[27] = 20; + SU2ToCGNS[28] = 18; + SU2ToCGNS[29] = 4; } -void CCGNSElementType::CreateDataPYRA_55(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPYRA_55(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PYRA_55 element is a quartic pyramid. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -567,47 +714,86 @@ void CCGNSElementType::CreateDataPYRA_55(unsigned short &VTK_Type, effect is currently ignored, i.e. it is assumed that the spacing in parameter space is uniform.*/ VTK_Type = PYRAMID; - nPoly = 4; - nDOFs = 55; + nPoly = 4; + nDOFs = 55; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 5; SU2ToCGNS[2] = 6; SU2ToCGNS[3] = 7; - SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 16; SU2ToCGNS[6] = 29; SU2ToCGNS[7] = 30; - SU2ToCGNS[8] = 31; SU2ToCGNS[9] = 8; SU2ToCGNS[10] = 15; SU2ToCGNS[11] = 36; - SU2ToCGNS[12] = 37; SU2ToCGNS[13] = 32; SU2ToCGNS[14] = 9; SU2ToCGNS[15] = 14; - SU2ToCGNS[16] = 35; SU2ToCGNS[17] = 34; SU2ToCGNS[18] = 33; SU2ToCGNS[19] = 10; - SU2ToCGNS[20] = 3; SU2ToCGNS[21] = 13; SU2ToCGNS[22] = 12; SU2ToCGNS[23] = 11; - SU2ToCGNS[24] = 2; SU2ToCGNS[25] = 17; SU2ToCGNS[26] = 38; SU2ToCGNS[27] = 39; - SU2ToCGNS[28] = 20; SU2ToCGNS[29] = 48; SU2ToCGNS[30] = 50; SU2ToCGNS[31] = 51; - SU2ToCGNS[32] = 41; SU2ToCGNS[33] = 47; SU2ToCGNS[34] = 53; SU2ToCGNS[35] = 52; - SU2ToCGNS[36] = 42; SU2ToCGNS[37] = 26; SU2ToCGNS[38] = 45; SU2ToCGNS[39] = 44; - SU2ToCGNS[40] = 23; SU2ToCGNS[41] = 18; SU2ToCGNS[42] = 40; SU2ToCGNS[43] = 21; - SU2ToCGNS[44] = 49; SU2ToCGNS[45] = 54; SU2ToCGNS[46] = 43; SU2ToCGNS[47] = 27; - SU2ToCGNS[48] = 46; SU2ToCGNS[49] = 24; SU2ToCGNS[50] = 19; SU2ToCGNS[51] = 22; - SU2ToCGNS[52] = 28; SU2ToCGNS[53] = 25; SU2ToCGNS[54] = 4; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 5; + SU2ToCGNS[2] = 6; + SU2ToCGNS[3] = 7; + SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 16; + SU2ToCGNS[6] = 29; + SU2ToCGNS[7] = 30; + SU2ToCGNS[8] = 31; + SU2ToCGNS[9] = 8; + SU2ToCGNS[10] = 15; + SU2ToCGNS[11] = 36; + SU2ToCGNS[12] = 37; + SU2ToCGNS[13] = 32; + SU2ToCGNS[14] = 9; + SU2ToCGNS[15] = 14; + SU2ToCGNS[16] = 35; + SU2ToCGNS[17] = 34; + SU2ToCGNS[18] = 33; + SU2ToCGNS[19] = 10; + SU2ToCGNS[20] = 3; + SU2ToCGNS[21] = 13; + SU2ToCGNS[22] = 12; + SU2ToCGNS[23] = 11; + SU2ToCGNS[24] = 2; + SU2ToCGNS[25] = 17; + SU2ToCGNS[26] = 38; + SU2ToCGNS[27] = 39; + SU2ToCGNS[28] = 20; + SU2ToCGNS[29] = 48; + SU2ToCGNS[30] = 50; + SU2ToCGNS[31] = 51; + SU2ToCGNS[32] = 41; + SU2ToCGNS[33] = 47; + SU2ToCGNS[34] = 53; + SU2ToCGNS[35] = 52; + SU2ToCGNS[36] = 42; + SU2ToCGNS[37] = 26; + SU2ToCGNS[38] = 45; + SU2ToCGNS[39] = 44; + SU2ToCGNS[40] = 23; + SU2ToCGNS[41] = 18; + SU2ToCGNS[42] = 40; + SU2ToCGNS[43] = 21; + SU2ToCGNS[44] = 49; + SU2ToCGNS[45] = 54; + SU2ToCGNS[46] = 43; + SU2ToCGNS[47] = 27; + SU2ToCGNS[48] = 46; + SU2ToCGNS[49] = 24; + SU2ToCGNS[50] = 19; + SU2ToCGNS[51] = 22; + SU2ToCGNS[52] = 28; + SU2ToCGNS[53] = 25; + SU2ToCGNS[54] = 4; } -void CCGNSElementType::CreateDataPENTA_6(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPENTA_6(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PENTA_6 element is a linear prism. The node numbering is the same in SU2 and CGNS. */ VTK_Type = PRISM; - nPoly = 1; - nDOFs = 6; + nPoly = 1; + nDOFs = 6; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 2; - SU2ToCGNS[3] = 3; SU2ToCGNS[4] = 4; SU2ToCGNS[5] = 5; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; + SU2ToCGNS[2] = 2; + SU2ToCGNS[3] = 3; + SU2ToCGNS[4] = 4; + SU2ToCGNS[5] = 5; } -void CCGNSElementType::CreateDataPENTA_18(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPENTA_18(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PENTA_18 element is a quadratic prism. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -618,22 +804,32 @@ void CCGNSElementType::CreateDataPENTA_18(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = PRISM; - nPoly = 2; - nDOFs = 18; + nPoly = 2; + nDOFs = 18; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 6; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 8; - SU2ToCGNS[4] = 7; SU2ToCGNS[5] = 2; SU2ToCGNS[6] = 9; SU2ToCGNS[7] = 15; - SU2ToCGNS[8] = 10; SU2ToCGNS[9] = 17; SU2ToCGNS[10] = 16; SU2ToCGNS[11] = 11; - SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 12; SU2ToCGNS[14] = 4; SU2ToCGNS[15] = 14; - SU2ToCGNS[16] = 13; SU2ToCGNS[17] = 5; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 6; + SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 8; + SU2ToCGNS[4] = 7; + SU2ToCGNS[5] = 2; + SU2ToCGNS[6] = 9; + SU2ToCGNS[7] = 15; + SU2ToCGNS[8] = 10; + SU2ToCGNS[9] = 17; + SU2ToCGNS[10] = 16; + SU2ToCGNS[11] = 11; + SU2ToCGNS[12] = 3; + SU2ToCGNS[13] = 12; + SU2ToCGNS[14] = 4; + SU2ToCGNS[15] = 14; + SU2ToCGNS[16] = 13; + SU2ToCGNS[17] = 5; } -void CCGNSElementType::CreateDataPENTA_40(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPENTA_40(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PENTA_40 element is a cubic prism. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -644,27 +840,54 @@ void CCGNSElementType::CreateDataPENTA_40(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = PRISM; - nPoly = 3; - nDOFs = 40; + nPoly = 3; + nDOFs = 40; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 6; SU2ToCGNS[2] = 7; SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 11; SU2ToCGNS[5] = 24; SU2ToCGNS[6] = 8; SU2ToCGNS[7] = 10; - SU2ToCGNS[8] = 9; SU2ToCGNS[9] = 2; SU2ToCGNS[10] = 12; SU2ToCGNS[11] = 25; - SU2ToCGNS[12] = 26; SU2ToCGNS[13] = 14; SU2ToCGNS[14] = 34; SU2ToCGNS[15] = 38; - SU2ToCGNS[16] = 29; SU2ToCGNS[17] = 33; SU2ToCGNS[18] = 30; SU2ToCGNS[19] = 16; - SU2ToCGNS[20] = 13; SU2ToCGNS[21] = 28; SU2ToCGNS[22] = 27; SU2ToCGNS[23] = 15; - SU2ToCGNS[24] = 35; SU2ToCGNS[25] = 39; SU2ToCGNS[26] = 32; SU2ToCGNS[27] = 36; - SU2ToCGNS[28] = 31; SU2ToCGNS[29] = 17; SU2ToCGNS[30] = 3; SU2ToCGNS[31] = 18; - SU2ToCGNS[32] = 19; SU2ToCGNS[33] = 4; SU2ToCGNS[34] = 23; SU2ToCGNS[35] = 37; - SU2ToCGNS[36] = 20; SU2ToCGNS[37] = 22; SU2ToCGNS[38] = 21; SU2ToCGNS[39] = 5; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 6; + SU2ToCGNS[2] = 7; + SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 11; + SU2ToCGNS[5] = 24; + SU2ToCGNS[6] = 8; + SU2ToCGNS[7] = 10; + SU2ToCGNS[8] = 9; + SU2ToCGNS[9] = 2; + SU2ToCGNS[10] = 12; + SU2ToCGNS[11] = 25; + SU2ToCGNS[12] = 26; + SU2ToCGNS[13] = 14; + SU2ToCGNS[14] = 34; + SU2ToCGNS[15] = 38; + SU2ToCGNS[16] = 29; + SU2ToCGNS[17] = 33; + SU2ToCGNS[18] = 30; + SU2ToCGNS[19] = 16; + SU2ToCGNS[20] = 13; + SU2ToCGNS[21] = 28; + SU2ToCGNS[22] = 27; + SU2ToCGNS[23] = 15; + SU2ToCGNS[24] = 35; + SU2ToCGNS[25] = 39; + SU2ToCGNS[26] = 32; + SU2ToCGNS[27] = 36; + SU2ToCGNS[28] = 31; + SU2ToCGNS[29] = 17; + SU2ToCGNS[30] = 3; + SU2ToCGNS[31] = 18; + SU2ToCGNS[32] = 19; + SU2ToCGNS[33] = 4; + SU2ToCGNS[34] = 23; + SU2ToCGNS[35] = 37; + SU2ToCGNS[36] = 20; + SU2ToCGNS[37] = 22; + SU2ToCGNS[38] = 21; + SU2ToCGNS[39] = 5; } -void CCGNSElementType::CreateDataPENTA_75(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataPENTA_75(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The PENTA_75 element is a quartic prism. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -678,36 +901,89 @@ void CCGNSElementType::CreateDataPENTA_75(unsigned short &VTK_Type, effect is currently ignored, i.e. it is assumed that the spacing in parameter space is uniform. */ VTK_Type = PRISM; - nPoly = 4; - nDOFs = 75; + nPoly = 4; + nDOFs = 75; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 6; SU2ToCGNS[2] = 7; SU2ToCGNS[3] = 8; - SU2ToCGNS[4] = 1; SU2ToCGNS[5] = 14; SU2ToCGNS[6] = 33; SU2ToCGNS[7] = 34; - SU2ToCGNS[8] = 9; SU2ToCGNS[9] = 13; SU2ToCGNS[10] = 35; SU2ToCGNS[11] = 10; - SU2ToCGNS[12] = 12; SU2ToCGNS[13] = 11; SU2ToCGNS[14] = 2; SU2ToCGNS[15] = 15; - SU2ToCGNS[16] = 36; SU2ToCGNS[17] = 37; SU2ToCGNS[18] = 38; SU2ToCGNS[19] = 18; - SU2ToCGNS[20] = 56; SU2ToCGNS[21] = 66; SU2ToCGNS[22] = 67; SU2ToCGNS[23] = 45; - SU2ToCGNS[24] = 55; SU2ToCGNS[25] = 68; SU2ToCGNS[26] = 46; SU2ToCGNS[27] = 54; - SU2ToCGNS[28] = 47; SU2ToCGNS[29] = 21; SU2ToCGNS[30] = 16; SU2ToCGNS[31] = 43; - SU2ToCGNS[32] = 44; SU2ToCGNS[33] = 39; SU2ToCGNS[34] = 19; SU2ToCGNS[35] = 57; - SU2ToCGNS[36] = 69; SU2ToCGNS[37] = 70; SU2ToCGNS[38] = 52; SU2ToCGNS[39] = 62; - SU2ToCGNS[40] = 71; SU2ToCGNS[41] = 53; SU2ToCGNS[42] = 61; SU2ToCGNS[43] = 48; - SU2ToCGNS[44] = 22; SU2ToCGNS[45] = 17; SU2ToCGNS[46] = 42; SU2ToCGNS[47] = 41; - SU2ToCGNS[48] = 40; SU2ToCGNS[49] = 20; SU2ToCGNS[50] = 58; SU2ToCGNS[51] = 72; - SU2ToCGNS[52] = 73; SU2ToCGNS[53] = 51; SU2ToCGNS[54] = 59; SU2ToCGNS[55] = 74; - SU2ToCGNS[56] = 50; SU2ToCGNS[57] = 60; SU2ToCGNS[58] = 49; SU2ToCGNS[59] = 23; - SU2ToCGNS[60] = 3; SU2ToCGNS[61] = 24; SU2ToCGNS[62] = 25; SU2ToCGNS[63] = 26; - SU2ToCGNS[64] = 4; SU2ToCGNS[65] = 32; SU2ToCGNS[66] = 63; SU2ToCGNS[67] = 64; - SU2ToCGNS[68] = 27; SU2ToCGNS[69] = 31; SU2ToCGNS[70] = 65; SU2ToCGNS[71] = 28; - SU2ToCGNS[72] = 30; SU2ToCGNS[73] = 29; SU2ToCGNS[74] = 5; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 6; + SU2ToCGNS[2] = 7; + SU2ToCGNS[3] = 8; + SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 14; + SU2ToCGNS[6] = 33; + SU2ToCGNS[7] = 34; + SU2ToCGNS[8] = 9; + SU2ToCGNS[9] = 13; + SU2ToCGNS[10] = 35; + SU2ToCGNS[11] = 10; + SU2ToCGNS[12] = 12; + SU2ToCGNS[13] = 11; + SU2ToCGNS[14] = 2; + SU2ToCGNS[15] = 15; + SU2ToCGNS[16] = 36; + SU2ToCGNS[17] = 37; + SU2ToCGNS[18] = 38; + SU2ToCGNS[19] = 18; + SU2ToCGNS[20] = 56; + SU2ToCGNS[21] = 66; + SU2ToCGNS[22] = 67; + SU2ToCGNS[23] = 45; + SU2ToCGNS[24] = 55; + SU2ToCGNS[25] = 68; + SU2ToCGNS[26] = 46; + SU2ToCGNS[27] = 54; + SU2ToCGNS[28] = 47; + SU2ToCGNS[29] = 21; + SU2ToCGNS[30] = 16; + SU2ToCGNS[31] = 43; + SU2ToCGNS[32] = 44; + SU2ToCGNS[33] = 39; + SU2ToCGNS[34] = 19; + SU2ToCGNS[35] = 57; + SU2ToCGNS[36] = 69; + SU2ToCGNS[37] = 70; + SU2ToCGNS[38] = 52; + SU2ToCGNS[39] = 62; + SU2ToCGNS[40] = 71; + SU2ToCGNS[41] = 53; + SU2ToCGNS[42] = 61; + SU2ToCGNS[43] = 48; + SU2ToCGNS[44] = 22; + SU2ToCGNS[45] = 17; + SU2ToCGNS[46] = 42; + SU2ToCGNS[47] = 41; + SU2ToCGNS[48] = 40; + SU2ToCGNS[49] = 20; + SU2ToCGNS[50] = 58; + SU2ToCGNS[51] = 72; + SU2ToCGNS[52] = 73; + SU2ToCGNS[53] = 51; + SU2ToCGNS[54] = 59; + SU2ToCGNS[55] = 74; + SU2ToCGNS[56] = 50; + SU2ToCGNS[57] = 60; + SU2ToCGNS[58] = 49; + SU2ToCGNS[59] = 23; + SU2ToCGNS[60] = 3; + SU2ToCGNS[61] = 24; + SU2ToCGNS[62] = 25; + SU2ToCGNS[63] = 26; + SU2ToCGNS[64] = 4; + SU2ToCGNS[65] = 32; + SU2ToCGNS[66] = 63; + SU2ToCGNS[67] = 64; + SU2ToCGNS[68] = 27; + SU2ToCGNS[69] = 31; + SU2ToCGNS[70] = 65; + SU2ToCGNS[71] = 28; + SU2ToCGNS[72] = 30; + SU2ToCGNS[73] = 29; + SU2ToCGNS[74] = 5; } -void CCGNSElementType::CreateDataHEXA_8(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataHEXA_8(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The HEXA_8 element is a linear hexahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes (not present in HEXA_8). @@ -718,19 +994,22 @@ void CCGNSElementType::CreateDataHEXA_8(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = HEXAHEDRON; - nPoly = 1; - nDOFs = 8; + nPoly = 1; + nDOFs = 8; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 1; SU2ToCGNS[2] = 3; SU2ToCGNS[3] = 2; - SU2ToCGNS[4] = 4; SU2ToCGNS[5] = 5; SU2ToCGNS[6] = 7; SU2ToCGNS[7] = 6; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 1; + SU2ToCGNS[2] = 3; + SU2ToCGNS[3] = 2; + SU2ToCGNS[4] = 4; + SU2ToCGNS[5] = 5; + SU2ToCGNS[6] = 7; + SU2ToCGNS[7] = 6; } -void CCGNSElementType::CreateDataHEXA_27(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataHEXA_27(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The HEXA_27 element is a quadratic hexahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -741,24 +1020,41 @@ void CCGNSElementType::CreateDataHEXA_27(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = HEXAHEDRON; - nPoly = 2; - nDOFs = 27; + nPoly = 2; + nDOFs = 27; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 8; SU2ToCGNS[2] = 1; SU2ToCGNS[3] = 11; - SU2ToCGNS[4] = 20; SU2ToCGNS[5] = 9; SU2ToCGNS[6] = 3; SU2ToCGNS[7] = 10; - SU2ToCGNS[8] = 2; SU2ToCGNS[9] = 12; SU2ToCGNS[10] = 21; SU2ToCGNS[11] = 13; - SU2ToCGNS[12] = 24; SU2ToCGNS[13] = 26; SU2ToCGNS[14] = 22; SU2ToCGNS[15] = 15; - SU2ToCGNS[16] = 23; SU2ToCGNS[17] = 14; SU2ToCGNS[18] = 4; SU2ToCGNS[19] = 16; - SU2ToCGNS[20] = 5; SU2ToCGNS[21] = 19; SU2ToCGNS[22] = 25; SU2ToCGNS[23] = 17; - SU2ToCGNS[24] = 7; SU2ToCGNS[25] = 18; SU2ToCGNS[26] = 6; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 8; + SU2ToCGNS[2] = 1; + SU2ToCGNS[3] = 11; + SU2ToCGNS[4] = 20; + SU2ToCGNS[5] = 9; + SU2ToCGNS[6] = 3; + SU2ToCGNS[7] = 10; + SU2ToCGNS[8] = 2; + SU2ToCGNS[9] = 12; + SU2ToCGNS[10] = 21; + SU2ToCGNS[11] = 13; + SU2ToCGNS[12] = 24; + SU2ToCGNS[13] = 26; + SU2ToCGNS[14] = 22; + SU2ToCGNS[15] = 15; + SU2ToCGNS[16] = 23; + SU2ToCGNS[17] = 14; + SU2ToCGNS[18] = 4; + SU2ToCGNS[19] = 16; + SU2ToCGNS[20] = 5; + SU2ToCGNS[21] = 19; + SU2ToCGNS[22] = 25; + SU2ToCGNS[23] = 17; + SU2ToCGNS[24] = 7; + SU2ToCGNS[25] = 18; + SU2ToCGNS[26] = 6; } -void CCGNSElementType::CreateDataHEXA_64(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataHEXA_64(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The HEXA_64 element is a cubic hexahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -769,33 +1065,78 @@ void CCGNSElementType::CreateDataHEXA_64(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = HEXAHEDRON; - nPoly = 3; - nDOFs = 64; + nPoly = 3; + nDOFs = 64; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 8; SU2ToCGNS[2] = 9; SU2ToCGNS[3] = 1; - SU2ToCGNS[4] = 15; SU2ToCGNS[5] = 32; SU2ToCGNS[6] = 33; SU2ToCGNS[7] = 10; - SU2ToCGNS[8] = 14; SU2ToCGNS[9] = 35; SU2ToCGNS[10] = 34; SU2ToCGNS[11] = 11; - SU2ToCGNS[12] = 3; SU2ToCGNS[13] = 13; SU2ToCGNS[14] = 12; SU2ToCGNS[15] = 2; - SU2ToCGNS[16] = 16; SU2ToCGNS[17] = 36; SU2ToCGNS[18] = 37; SU2ToCGNS[19] = 18; - SU2ToCGNS[20] = 49; SU2ToCGNS[21] = 56; SU2ToCGNS[22] = 57; SU2ToCGNS[23] = 40; - SU2ToCGNS[24] = 48; SU2ToCGNS[25] = 59; SU2ToCGNS[26] = 58; SU2ToCGNS[27] = 41; - SU2ToCGNS[28] = 22; SU2ToCGNS[29] = 45; SU2ToCGNS[30] = 44; SU2ToCGNS[31] = 20; - SU2ToCGNS[32] = 17; SU2ToCGNS[33] = 39; SU2ToCGNS[34] = 38; SU2ToCGNS[35] = 19; - SU2ToCGNS[36] = 50; SU2ToCGNS[37] = 60; SU2ToCGNS[38] = 61; SU2ToCGNS[39] = 43; - SU2ToCGNS[40] = 51; SU2ToCGNS[41] = 63; SU2ToCGNS[42] = 62; SU2ToCGNS[43] = 42; - SU2ToCGNS[44] = 23; SU2ToCGNS[45] = 46; SU2ToCGNS[46] = 47; SU2ToCGNS[47] = 21; - SU2ToCGNS[48] = 4; SU2ToCGNS[49] = 24; SU2ToCGNS[50] = 25; SU2ToCGNS[51] = 5; - SU2ToCGNS[52] = 31; SU2ToCGNS[53] = 52; SU2ToCGNS[54] = 53; SU2ToCGNS[55] = 26; - SU2ToCGNS[56] = 30; SU2ToCGNS[57] = 55; SU2ToCGNS[58] = 54; SU2ToCGNS[59] = 27; - SU2ToCGNS[60] = 7; SU2ToCGNS[61] = 29; SU2ToCGNS[62] = 28; SU2ToCGNS[63] = 6; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 8; + SU2ToCGNS[2] = 9; + SU2ToCGNS[3] = 1; + SU2ToCGNS[4] = 15; + SU2ToCGNS[5] = 32; + SU2ToCGNS[6] = 33; + SU2ToCGNS[7] = 10; + SU2ToCGNS[8] = 14; + SU2ToCGNS[9] = 35; + SU2ToCGNS[10] = 34; + SU2ToCGNS[11] = 11; + SU2ToCGNS[12] = 3; + SU2ToCGNS[13] = 13; + SU2ToCGNS[14] = 12; + SU2ToCGNS[15] = 2; + SU2ToCGNS[16] = 16; + SU2ToCGNS[17] = 36; + SU2ToCGNS[18] = 37; + SU2ToCGNS[19] = 18; + SU2ToCGNS[20] = 49; + SU2ToCGNS[21] = 56; + SU2ToCGNS[22] = 57; + SU2ToCGNS[23] = 40; + SU2ToCGNS[24] = 48; + SU2ToCGNS[25] = 59; + SU2ToCGNS[26] = 58; + SU2ToCGNS[27] = 41; + SU2ToCGNS[28] = 22; + SU2ToCGNS[29] = 45; + SU2ToCGNS[30] = 44; + SU2ToCGNS[31] = 20; + SU2ToCGNS[32] = 17; + SU2ToCGNS[33] = 39; + SU2ToCGNS[34] = 38; + SU2ToCGNS[35] = 19; + SU2ToCGNS[36] = 50; + SU2ToCGNS[37] = 60; + SU2ToCGNS[38] = 61; + SU2ToCGNS[39] = 43; + SU2ToCGNS[40] = 51; + SU2ToCGNS[41] = 63; + SU2ToCGNS[42] = 62; + SU2ToCGNS[43] = 42; + SU2ToCGNS[44] = 23; + SU2ToCGNS[45] = 46; + SU2ToCGNS[46] = 47; + SU2ToCGNS[47] = 21; + SU2ToCGNS[48] = 4; + SU2ToCGNS[49] = 24; + SU2ToCGNS[50] = 25; + SU2ToCGNS[51] = 5; + SU2ToCGNS[52] = 31; + SU2ToCGNS[53] = 52; + SU2ToCGNS[54] = 53; + SU2ToCGNS[55] = 26; + SU2ToCGNS[56] = 30; + SU2ToCGNS[57] = 55; + SU2ToCGNS[58] = 54; + SU2ToCGNS[59] = 27; + SU2ToCGNS[60] = 7; + SU2ToCGNS[61] = 29; + SU2ToCGNS[62] = 28; + SU2ToCGNS[63] = 6; } -void CCGNSElementType::CreateDataHEXA_125(unsigned short &VTK_Type, - unsigned short &nPoly, - unsigned short &nDOFs, - vector &SU2ToCGNS) { - +void CCGNSElementType::CreateDataHEXA_125(unsigned short& VTK_Type, unsigned short& nPoly, unsigned short& nDOFs, + vector& SU2ToCGNS) { /* The HEXA_125 element is a quartic hexahedron. In CGNS the nodes are numbered as follows: - First the vertex nodes. - Second the edge nodes. @@ -806,35 +1147,135 @@ void CCGNSElementType::CreateDataHEXA_125(unsigned short &VTK_Type, from node 0 along the second edge and the k-direction from node 0 along the third edge. */ VTK_Type = HEXAHEDRON; - nPoly = 4; - nDOFs = 125; + nPoly = 4; + nDOFs = 125; SU2ToCGNS.resize(nDOFs); - SU2ToCGNS[0] = 0; SU2ToCGNS[1] = 8; SU2ToCGNS[2] = 9; SU2ToCGNS[3] = 10; SU2ToCGNS[4] = 1; - SU2ToCGNS[5] = 19; SU2ToCGNS[6] = 44; SU2ToCGNS[7] = 45; SU2ToCGNS[8] = 46; SU2ToCGNS[9] = 11; - SU2ToCGNS[10] = 18; SU2ToCGNS[11] = 51; SU2ToCGNS[12] = 52; SU2ToCGNS[13] = 47; SU2ToCGNS[14] = 12; - SU2ToCGNS[15] = 17; SU2ToCGNS[16] = 50; SU2ToCGNS[17] = 49; SU2ToCGNS[18] = 48; SU2ToCGNS[19] = 13; - SU2ToCGNS[20] = 3; SU2ToCGNS[21] = 16; SU2ToCGNS[22] = 15; SU2ToCGNS[23] = 14; SU2ToCGNS[24] = 2; - SU2ToCGNS[25] = 20; SU2ToCGNS[26] = 53; SU2ToCGNS[27] = 54; SU2ToCGNS[28] = 55; SU2ToCGNS[29] = 23; - SU2ToCGNS[30] = 82; SU2ToCGNS[31] = 98; SU2ToCGNS[32] = 99; SU2ToCGNS[33] = 100; SU2ToCGNS[34] = 62; - SU2ToCGNS[35] = 81; SU2ToCGNS[36] = 105; SU2ToCGNS[37] = 106; SU2ToCGNS[38] = 101; SU2ToCGNS[39] = 63; - SU2ToCGNS[40] = 80; SU2ToCGNS[41] = 104; SU2ToCGNS[42] = 103; SU2ToCGNS[43] = 102; SU2ToCGNS[44] = 64; - SU2ToCGNS[45] = 29; SU2ToCGNS[46] = 73; SU2ToCGNS[47] = 72; SU2ToCGNS[48] = 71; SU2ToCGNS[49] = 26; - SU2ToCGNS[50] = 21; SU2ToCGNS[51] = 60; SU2ToCGNS[52] = 61; SU2ToCGNS[53] = 56; SU2ToCGNS[54] = 24; - SU2ToCGNS[55] = 83; SU2ToCGNS[56] = 107; SU2ToCGNS[57] = 108; SU2ToCGNS[58] = 109; SU2ToCGNS[59] = 69; - SU2ToCGNS[60] = 88; SU2ToCGNS[61] = 114; SU2ToCGNS[62] = 115; SU2ToCGNS[63] = 110; SU2ToCGNS[64] = 70; - SU2ToCGNS[65] = 87; SU2ToCGNS[66] = 113; SU2ToCGNS[67] = 112; SU2ToCGNS[68] = 111; SU2ToCGNS[69] = 65; - SU2ToCGNS[70] = 30; SU2ToCGNS[71] = 74; SU2ToCGNS[72] = 79; SU2ToCGNS[73] = 78; SU2ToCGNS[74] = 27; - SU2ToCGNS[75] = 22; SU2ToCGNS[76] = 59; SU2ToCGNS[77] = 58; SU2ToCGNS[78] = 57; SU2ToCGNS[79] = 25; - SU2ToCGNS[80] = 84; SU2ToCGNS[81] = 116; SU2ToCGNS[82] = 117; SU2ToCGNS[83] = 118; SU2ToCGNS[84] = 68; - SU2ToCGNS[85] = 85; SU2ToCGNS[86] = 123; SU2ToCGNS[87] = 124; SU2ToCGNS[88] = 119; SU2ToCGNS[89] = 67; - SU2ToCGNS[90] = 86; SU2ToCGNS[91] = 122; SU2ToCGNS[92] = 121; SU2ToCGNS[93] = 120; SU2ToCGNS[94] = 66; - SU2ToCGNS[95] = 31; SU2ToCGNS[96] = 75; SU2ToCGNS[97] = 76; SU2ToCGNS[98] = 77; SU2ToCGNS[99] = 28; - SU2ToCGNS[100] = 4; SU2ToCGNS[101] = 32; SU2ToCGNS[102] = 33; SU2ToCGNS[103] = 34; SU2ToCGNS[104] = 5; - SU2ToCGNS[105] = 43; SU2ToCGNS[106] = 89; SU2ToCGNS[107] = 90; SU2ToCGNS[108] = 91; SU2ToCGNS[109] = 35; - SU2ToCGNS[110] = 42; SU2ToCGNS[111] = 96; SU2ToCGNS[112] = 97; SU2ToCGNS[113] = 92; SU2ToCGNS[114] = 36; - SU2ToCGNS[115] = 41; SU2ToCGNS[116] = 95; SU2ToCGNS[117] = 94; SU2ToCGNS[118] = 93; SU2ToCGNS[119] = 37; - SU2ToCGNS[120] = 7; SU2ToCGNS[121] = 40; SU2ToCGNS[122] = 39; SU2ToCGNS[123] = 38; SU2ToCGNS[124] = 6; + SU2ToCGNS[0] = 0; + SU2ToCGNS[1] = 8; + SU2ToCGNS[2] = 9; + SU2ToCGNS[3] = 10; + SU2ToCGNS[4] = 1; + SU2ToCGNS[5] = 19; + SU2ToCGNS[6] = 44; + SU2ToCGNS[7] = 45; + SU2ToCGNS[8] = 46; + SU2ToCGNS[9] = 11; + SU2ToCGNS[10] = 18; + SU2ToCGNS[11] = 51; + SU2ToCGNS[12] = 52; + SU2ToCGNS[13] = 47; + SU2ToCGNS[14] = 12; + SU2ToCGNS[15] = 17; + SU2ToCGNS[16] = 50; + SU2ToCGNS[17] = 49; + SU2ToCGNS[18] = 48; + SU2ToCGNS[19] = 13; + SU2ToCGNS[20] = 3; + SU2ToCGNS[21] = 16; + SU2ToCGNS[22] = 15; + SU2ToCGNS[23] = 14; + SU2ToCGNS[24] = 2; + SU2ToCGNS[25] = 20; + SU2ToCGNS[26] = 53; + SU2ToCGNS[27] = 54; + SU2ToCGNS[28] = 55; + SU2ToCGNS[29] = 23; + SU2ToCGNS[30] = 82; + SU2ToCGNS[31] = 98; + SU2ToCGNS[32] = 99; + SU2ToCGNS[33] = 100; + SU2ToCGNS[34] = 62; + SU2ToCGNS[35] = 81; + SU2ToCGNS[36] = 105; + SU2ToCGNS[37] = 106; + SU2ToCGNS[38] = 101; + SU2ToCGNS[39] = 63; + SU2ToCGNS[40] = 80; + SU2ToCGNS[41] = 104; + SU2ToCGNS[42] = 103; + SU2ToCGNS[43] = 102; + SU2ToCGNS[44] = 64; + SU2ToCGNS[45] = 29; + SU2ToCGNS[46] = 73; + SU2ToCGNS[47] = 72; + SU2ToCGNS[48] = 71; + SU2ToCGNS[49] = 26; + SU2ToCGNS[50] = 21; + SU2ToCGNS[51] = 60; + SU2ToCGNS[52] = 61; + SU2ToCGNS[53] = 56; + SU2ToCGNS[54] = 24; + SU2ToCGNS[55] = 83; + SU2ToCGNS[56] = 107; + SU2ToCGNS[57] = 108; + SU2ToCGNS[58] = 109; + SU2ToCGNS[59] = 69; + SU2ToCGNS[60] = 88; + SU2ToCGNS[61] = 114; + SU2ToCGNS[62] = 115; + SU2ToCGNS[63] = 110; + SU2ToCGNS[64] = 70; + SU2ToCGNS[65] = 87; + SU2ToCGNS[66] = 113; + SU2ToCGNS[67] = 112; + SU2ToCGNS[68] = 111; + SU2ToCGNS[69] = 65; + SU2ToCGNS[70] = 30; + SU2ToCGNS[71] = 74; + SU2ToCGNS[72] = 79; + SU2ToCGNS[73] = 78; + SU2ToCGNS[74] = 27; + SU2ToCGNS[75] = 22; + SU2ToCGNS[76] = 59; + SU2ToCGNS[77] = 58; + SU2ToCGNS[78] = 57; + SU2ToCGNS[79] = 25; + SU2ToCGNS[80] = 84; + SU2ToCGNS[81] = 116; + SU2ToCGNS[82] = 117; + SU2ToCGNS[83] = 118; + SU2ToCGNS[84] = 68; + SU2ToCGNS[85] = 85; + SU2ToCGNS[86] = 123; + SU2ToCGNS[87] = 124; + SU2ToCGNS[88] = 119; + SU2ToCGNS[89] = 67; + SU2ToCGNS[90] = 86; + SU2ToCGNS[91] = 122; + SU2ToCGNS[92] = 121; + SU2ToCGNS[93] = 120; + SU2ToCGNS[94] = 66; + SU2ToCGNS[95] = 31; + SU2ToCGNS[96] = 75; + SU2ToCGNS[97] = 76; + SU2ToCGNS[98] = 77; + SU2ToCGNS[99] = 28; + SU2ToCGNS[100] = 4; + SU2ToCGNS[101] = 32; + SU2ToCGNS[102] = 33; + SU2ToCGNS[103] = 34; + SU2ToCGNS[104] = 5; + SU2ToCGNS[105] = 43; + SU2ToCGNS[106] = 89; + SU2ToCGNS[107] = 90; + SU2ToCGNS[108] = 91; + SU2ToCGNS[109] = 35; + SU2ToCGNS[110] = 42; + SU2ToCGNS[111] = 96; + SU2ToCGNS[112] = 97; + SU2ToCGNS[113] = 92; + SU2ToCGNS[114] = 36; + SU2ToCGNS[115] = 41; + SU2ToCGNS[116] = 95; + SU2ToCGNS[117] = 94; + SU2ToCGNS[118] = 93; + SU2ToCGNS[119] = 37; + SU2ToCGNS[120] = 7; + SU2ToCGNS[121] = 40; + SU2ToCGNS[122] = 39; + SU2ToCGNS[123] = 38; + SU2ToCGNS[124] = 6; } #endif diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp index 379176ad6c9..53697f65958 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp @@ -29,8 +29,7 @@ #include "../../../include/toolboxes/CLinearPartitioner.hpp" #include "../../../include/geometry/meshreader/CCGNSMeshReaderBase.hpp" -CCGNSMeshReaderBase::CCGNSMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, - unsigned short val_nZone) +CCGNSMeshReaderBase::CCGNSMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : CMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS /*--- Leave the option to do something in the future here. ---*/ @@ -355,42 +354,75 @@ string CCGNSMeshReaderBase::GetCGNSElementType(ElementType_t val_elem_type, int& val_vtk_type = 1; SU2_MPI::Error("Vertex elements detected. Please remove.", CURRENT_FUNCTION); break; - case BAR_2: case BAR_3: case BAR_4: case BAR_5: + case BAR_2: + case BAR_3: + case BAR_4: + case BAR_5: elem_name = "Line"; val_vtk_type = 3; - if (dimension == 3) - SU2_MPI::Error("Line elements detected in a 3D mesh. Please remove.", - CURRENT_FUNCTION); + if (dimension == 3) SU2_MPI::Error("Line elements detected in a 3D mesh. Please remove.", CURRENT_FUNCTION); break; - case TRI_3: case TRI_6: case TRI_9: case TRI_10: - case TRI_12: case TRI_15: + case TRI_3: + case TRI_6: + case TRI_9: + case TRI_10: + case TRI_12: + case TRI_15: elem_name = "Triangle"; val_vtk_type = 5; break; - case QUAD_4: case QUAD_8: case QUAD_9: case QUAD_12: - case QUAD_16: case QUAD_P4_16: case QUAD_25: + case QUAD_4: + case QUAD_8: + case QUAD_9: + case QUAD_12: + case QUAD_16: + case QUAD_P4_16: + case QUAD_25: elem_name = "Quadrilateral"; val_vtk_type = 9; break; - case TETRA_4: case TETRA_10: case TETRA_16: case TETRA_20: - case TETRA_22: case TETRA_34: case TETRA_35: + case TETRA_4: + case TETRA_10: + case TETRA_16: + case TETRA_20: + case TETRA_22: + case TETRA_34: + case TETRA_35: elem_name = "Tetrahedron"; val_vtk_type = 10; break; - case HEXA_8: case HEXA_20: case HEXA_27: case HEXA_32: - case HEXA_56: case HEXA_64: case HEXA_44: case HEXA_98: + case HEXA_8: + case HEXA_20: + case HEXA_27: + case HEXA_32: + case HEXA_56: + case HEXA_64: + case HEXA_44: + case HEXA_98: case HEXA_125: elem_name = "Hexahedron"; val_vtk_type = 12; break; - case PENTA_6: case PENTA_15: case PENTA_18: case PENTA_24: - case PENTA_38: case PENTA_40: case PENTA_33: case PENTA_66: + case PENTA_6: + case PENTA_15: + case PENTA_18: + case PENTA_24: + case PENTA_38: + case PENTA_40: + case PENTA_33: + case PENTA_66: case PENTA_75: elem_name = "Prism"; val_vtk_type = 13; break; - case PYRA_5: case PYRA_14: case PYRA_13: case PYRA_21: - case PYRA_29: case PYRA_30: case PYRA_P4_29: case PYRA_50: + case PYRA_5: + case PYRA_14: + case PYRA_13: + case PYRA_21: + case PYRA_29: + case PYRA_30: + case PYRA_P4_29: + case PYRA_50: case PYRA_55: elem_name = "Pyramid"; val_vtk_type = 14; diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp index 48c0b267cfb..1d2c1f22f01 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -30,8 +30,7 @@ #include "../../../include/geometry/meshreader/CCGNSMeshReaderFEM.hpp" #include "../../../include/geometry/meshreader/CCGNSElementType.hpp" -CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, - unsigned short val_nZone) +CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : CCGNSMeshReaderBase(val_config, val_iZone, val_nZone) { #ifdef HAVE_CGNS OpenCGNSFile(config->GetMesh_FileName()); @@ -65,65 +64,59 @@ CCGNSMeshReaderFEM::CCGNSMeshReaderFEM(const CConfig* val_config, unsigned short CCGNSMeshReaderFEM::~CCGNSMeshReaderFEM() = default; #ifdef HAVE_CGNS -void CCGNSMeshReaderFEM::ReadCGNSConnectivityRangeSection(const int val_section, - const unsigned long val_firstIndex, - const unsigned long val_lastIndex, - unsigned long &elemCount, - unsigned long &localElemCount, - vector &localConn) { - +void CCGNSMeshReaderFEM::ReadCGNSConnectivityRangeSection(const int val_section, const unsigned long val_firstIndex, + const unsigned long val_lastIndex, unsigned long& elemCount, + unsigned long& localElemCount, + vector& localConn) { /*--- Read the connectivity details for this section. ---*/ int nbndry, parent_flag; cgsize_t startE, endE; ElementType_t elemType; char sectionName[CGNS_STRING_SIZE]; - if(cg_section_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, sectionName, - &elemType, &startE, &endE, &nbndry, &parent_flag)) + if (cg_section_read(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, sectionName, &elemType, &startE, &endE, &nbndry, + &parent_flag)) cg_error_exit(); /*--- Determine the number of elements in this section and update the element counters accordingly. ---*/ - const unsigned long nElemSection = (endE-startE+1); + const unsigned long nElemSection = (endE - startE + 1); const unsigned long elemCountOld = elemCount; elemCount += nElemSection; /*--- Check for overlap with the element range this rank is responsible for. ---*/ const unsigned long indBegOverlap = max(elemCountOld, val_firstIndex); - const unsigned long indEndOverlap = min(elemCount, val_lastIndex); - - if(indEndOverlap > indBegOverlap) { + const unsigned long indEndOverlap = min(elemCount, val_lastIndex); + if (indEndOverlap > indBegOverlap) { /*--- This rank must read element data from this connectivity section. Determine the offset relative to the start of this section and the number of elements to be read by this rank. ---*/ const unsigned long offsetRank = indBegOverlap - elemCountOld; - const unsigned long nElemRank = indEndOverlap - indBegOverlap; + const unsigned long nElemRank = indEndOverlap - indBegOverlap; nElems[val_section] = nElemRank; /*--- Determine the index range to be read for this rank. ---*/ const cgsize_t iBeg = startE + offsetRank; - const cgsize_t iEnd = iBeg + nElemRank -1; + const cgsize_t iEnd = iBeg + nElemRank - 1; /*--- Determine the size of the vector needed to read the connectivity data from the CGNS file. ---*/ cgsize_t sizeNeeded; - if (cg_ElementPartialSize(cgnsFileID, cgnsBase, cgnsZone, val_section+1, - iBeg, iEnd, &sizeNeeded) != CG_OK) + if (cg_ElementPartialSize(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, iBeg, iEnd, &sizeNeeded) != CG_OK) cg_error_exit(); /*--- Allocate the memory for the connectivity and read the data. ---*/ vector connCGNSVec(sizeNeeded); if (elemType == MIXED) { - vector connCGNSOffsetVec(iEnd-iBeg+2); - if(cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, - iBeg, iEnd, connCGNSVec.data(), - connCGNSOffsetVec.data(), NULL) != CG_OK) + vector connCGNSOffsetVec(iEnd - iBeg + 2); + if (cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, iBeg, iEnd, connCGNSVec.data(), + connCGNSOffsetVec.data(), NULL) != CG_OK) cg_error_exit(); } else { - if(cg_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, - iBeg, iEnd, connCGNSVec.data(), NULL) != CG_OK) + if (cg_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, iBeg, iEnd, connCGNSVec.data(), + NULL) != CG_OK) cg_error_exit(); } @@ -132,15 +125,14 @@ void CCGNSMeshReaderFEM::ReadCGNSConnectivityRangeSection(const int CCGNSElementType CGNSElem; std::vector connSU2; ElementType_t typeElem = elemType; - const cgsize_t *connCGNS = connCGNSVec.data(); + const cgsize_t* connCGNS = connCGNSVec.data(); /*--- Loop over the elements just read. ---*/ - for(unsigned long i=0; i SINGLE_NODE) @@ -168,33 +159,29 @@ void CCGNSMeshReaderFEM::ReadCGNSVolumeElementConnectivity(void) { } /*--- Get a partitioner to help with linear partitioning. ---*/ - CLinearPartitioner elemPartitioner(numberOfGlobalElements,0); + CLinearPartitioner elemPartitioner(numberOfGlobalElements, 0); /*--- Determine the index of the first and last element to be stored on this rank and the number of local elements. ---*/ const unsigned long firstIndex = elemPartitioner.GetFirstIndexOnRank(rank); - const unsigned long lastIndex = elemPartitioner.GetLastIndexOnRank(rank); + const unsigned long lastIndex = elemPartitioner.GetLastIndexOnRank(rank); numberOfLocalElements = elemPartitioner.GetSizeOnRank(rank); /*--- Loop over the section and check for a section with volume elements. ---*/ unsigned long elemCount = 0, localElemCount = 0; - for(int s=0; s localFaces; @@ -213,19 +200,16 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceElementConnectivity(void) { /*--- Loop over the number of sections and check for a surface. ---*/ int markerCount = 0; - for(int s=0; s &localFaces, - unsigned long &nSurfElem, - vector &surfConn) { - +void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val_section, const vector& localFaces, + unsigned long& nSurfElem, vector& surfConn) { /*--- Initialize nSurfElem to zero. ---*/ nSurfElem = 0; @@ -249,46 +230,43 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val ElementType_t elemType; char sectionName[CGNS_STRING_SIZE]; - if(cg_section_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, sectionName, - &elemType, &startE, &endE, &nbndry, &parent_flag)) + if (cg_section_read(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, sectionName, &elemType, &startE, &endE, &nbndry, + &parent_flag)) cg_error_exit(); - const unsigned long nElemSection = (endE-startE+1); + const unsigned long nElemSection = (endE - startE + 1); /*--- Determine the number of chunks used for the reading of the surface elements. This is done to avoid a memory bottleneck for extremely big cases. For reasonably sized grids this connectivity can be read in a single call. ---*/ - unsigned long nChunks = nElemSection/localFaces.size(); - if(nChunks*localFaces.size() != nElemSection) ++nChunks; - const unsigned long nElemChunk = nElemSection/nChunks; + unsigned long nChunks = nElemSection / localFaces.size(); + if (nChunks * localFaces.size() != nElemSection) ++nChunks; + const unsigned long nElemChunk = nElemSection / nChunks; /*--- Loop over the number of chunks. ---*/ - for(unsigned long iChunk=0; iChunk connCGNSVec(sizeNeeded); if (elemType == MIXED) { - vector connCGNSOffsetVec(iEnd-iBeg+2); - if(cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, - iBeg, iEnd, connCGNSVec.data(), - connCGNSOffsetVec.data(), NULL) != CG_OK) + vector connCGNSOffsetVec(iEnd - iBeg + 2); + if (cg_poly_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, iBeg, iEnd, connCGNSVec.data(), + connCGNSOffsetVec.data(), NULL) != CG_OK) cg_error_exit(); } else { - if(cg_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section+1, - iBeg, iEnd, connCGNSVec.data(), NULL) != CG_OK) + if (cg_elements_partial_read(cgnsFileID, cgnsBase, cgnsZone, val_section + 1, iBeg, iEnd, connCGNSVec.data(), + NULL) != CG_OK) cg_error_exit(); } @@ -297,72 +275,70 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val CCGNSElementType CGNSElem; std::vector connSU2; ElementType_t typeElem = elemType; - const cgsize_t *connCGNS = connCGNSVec.data(); + const cgsize_t* connCGNS = connCGNSVec.data(); /*--- Loop over the elements just read. ---*/ - for(cgsize_t i=iBeg; i<=iEnd; ++i) { - + for (cgsize_t i = iBeg; i <= iEnd; ++i) { /*--- Determine the element type for this element if this is a mixed connectivity and set the pointer to the actual connectivity data. ---*/ - if(elemType == MIXED) { - typeElem = (ElementType_t) connCGNS[0]; + if (elemType == MIXED) { + typeElem = (ElementType_t)connCGNS[0]; ++connCGNS; } /*--- Convert the CGNS connectivity to SU2 connectivity and update the pointer for the next surface element. ---*/ - const unsigned long globalID = i-1; + const unsigned long globalID = i - 1; CGNSElem.CGNSToSU2(typeElem, globalID, connCGNS, connSU2); connCGNS += connSU2[3]; /*--- Easier storage of the VTK type, polynomial degree and number of DOFs of the surface element. ---*/ - const unsigned short VTK_Type = (unsigned short) connSU2[0]; - const unsigned short nPolyGrid = (unsigned short) connSU2[1]; - const unsigned short nDOFsGrid = (unsigned short) connSU2[3]; + const unsigned short VTK_Type = (unsigned short)connSU2[0]; + const unsigned short nPolyGrid = (unsigned short)connSU2[1]; + const unsigned short nDOFsGrid = (unsigned short)connSU2[3]; /*--- Make a distinction between the possible element surface types and determine the corner points in local numbering of the element. ---*/ const unsigned short nDOFEdgeGrid = nPolyGrid + 1; CFaceOfElement thisFace; - thisFace.cornerPoints[0] = 0; thisFace.cornerPoints[1] = nPolyGrid; + thisFace.cornerPoints[0] = 0; + thisFace.cornerPoints[1] = nPolyGrid; - switch( VTK_Type ) { + switch (VTK_Type) { case LINE: thisFace.nCornerPoints = 2; break; case TRIANGLE: thisFace.nCornerPoints = 3; - thisFace.cornerPoints[2] = nDOFsGrid -1; + thisFace.cornerPoints[2] = nDOFsGrid - 1; break; case QUADRILATERAL: thisFace.nCornerPoints = 4; - thisFace.cornerPoints[2] = nPolyGrid*nDOFEdgeGrid; - thisFace.cornerPoints[3] = nDOFsGrid -1; + thisFace.cornerPoints[2] = nPolyGrid * nDOFEdgeGrid; + thisFace.cornerPoints[3] = nDOFsGrid - 1; break; default: ostringstream message; - message << "Unsupported FEM boundary element value, " << typeElem - << ", in surface section " << sectionName; + message << "Unsupported FEM boundary element value, " << typeElem << ", in surface section " << sectionName; SU2_MPI::Error(message.str(), CURRENT_FUNCTION); } /*--- Convert the local numbering of thisFace to global numbering and create a unique numbering of corner points. ---*/ - for(unsigned short j=0; j::const_iterator low; low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); - if(low != localFaces.end()) { - if( !(thisFace < *low) ) { - + if (low != localFaces.end()) { + if (!(thisFace < *low)) { /*--- Update the number of local surface elements. ---*/ ++nSurfElem; @@ -383,24 +359,22 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val #endif void CCGNSMeshReaderFEM::CommPointCoordinates(void) { - /*--- Determine the linear partitioning of the points. ---*/ - CLinearPartitioner pointPartitioner(numberOfGlobalPoints,0); + CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); /*--- Loop over the local elements to determine the global point IDs to be stored on this rank. --*/ unsigned long ind = 0; - for(unsigned long i=0; i > pointBuf(size, vector(0)); - for(unsigned long i=0; i sendToRank(size, 0); - vector startingIndRanksInPoint(size+1); + vector startingIndRanksInPoint(size + 1); startingIndRanksInPoint[0] = 0; - for(int i=0; i sizeRecv(size, 1); - SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), - MPI_INT, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Reduce_scatter(sendToRank.data(), &nRankRecv, sizeRecv.data(), MPI_INT, MPI_SUM, SU2_MPI::GetComm()); /*--- Send out the messages with the global point numbers. Use nonblocking sends to avoid deadlock. ---*/ vector sendReqs(nRankSend); nRankSend = 0; - for(int i=0; i pointRecvBuf(sizeMess); - coorReturnBuf[i].resize(dimension*sizeMess); + coorReturnBuf[i].resize(dimension * sizeMess); /* Receive the message using a blocking receive. */ - SU2_MPI::Recv(pointRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, - source, rank, SU2_MPI::GetComm(), &status); + SU2_MPI::Recv(pointRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, source, rank, SU2_MPI::GetComm(), &status); /*--- Loop over the nodes just received and fill the return communication buffer with the coordinates of the requested nodes. ---*/ - for(int j=0; j= static_cast(nPointsRead)) + if (kk < 0 || kk >= static_cast(nPointsRead)) SU2_MPI::Error("Invalid point requested. This should not happen.", CURRENT_FUNCTION); - for(int k=0; k coorRecvBuf(dimension*pointBuf[source].size()); + vector coorRecvBuf(dimension * pointBuf[source].size()); /* Receive the message using a blocking receive. */ - SU2_MPI::Recv(coorRecvBuf.data(), coorRecvBuf.size(), MPI_DOUBLE, - source, rank+1, SU2_MPI::GetComm(), &status); + SU2_MPI::Recv(coorRecvBuf.data(), coorRecvBuf.size(), MPI_DOUBLE, source, rank + 1, SU2_MPI::GetComm(), &status); /*--- Loop over the points just received. ---*/ - for(unsigned long j=0; jGetMesh_FileName()); diff --git a/Common/src/geometry/meshreader/CMeshReaderBase.cpp b/Common/src/geometry/meshreader/CMeshReaderBase.cpp index 478aa9dc2e3..bb20e0d97b9 100644 --- a/Common/src/geometry/meshreader/CMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CMeshReaderBase.cpp @@ -31,30 +31,27 @@ CMeshReaderBase::CMeshReaderBase(const CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : rank(SU2_MPI::GetRank()), size(SU2_MPI::GetSize()), config(val_config) {} -void CMeshReaderBase::DetermineFacesVolumeElements(vector &localFaces) { - +void CMeshReaderBase::DetermineFacesVolumeElements(vector& localFaces) { /*--- Loop over the locally stored volume elements. ---*/ unsigned long ind = 0; - for(unsigned long k=0; k &local } /*--- Update the index for the next element. ---*/ - const unsigned long nDOFsGrid = localVolumeElementConnectivity[ind+3]; - ind += nDOFsGrid+5; + const unsigned long nDOFsGrid = localVolumeElementConnectivity[ind + 3]; + ind += nDOFsGrid + 5; } /*--- Sort localFaces in increasing order and remove the double entities, @@ -74,29 +71,25 @@ void CMeshReaderBase::DetermineFacesVolumeElements(vector &local localFaces.erase(lastFace, localFaces.end()); } -void CMeshReaderBase::GetCornerPointsAllFaces(const unsigned long *elemInfo, - unsigned short &numFaces, - unsigned short nPointsPerFace[], - unsigned long faceConn[6][4]) { - +void CMeshReaderBase::GetCornerPointsAllFaces(const unsigned long* elemInfo, unsigned short& numFaces, + unsigned short nPointsPerFace[], unsigned long faceConn[6][4]) { /*--- Retrieve the element type, polynomial degree of the grid and number of DOFs for this element and set the pointer for the connectivity information. ---*/ - const unsigned short VTK_Type = (const unsigned short) elemInfo[0]; - const unsigned short nPolyGrid = (const unsigned short) elemInfo[1]; - const unsigned short nDOFsGrid = (const unsigned short) elemInfo[3]; - const unsigned long *conn = elemInfo + 5; + const unsigned short VTK_Type = (const unsigned short)elemInfo[0]; + const unsigned short nPolyGrid = (const unsigned short)elemInfo[1]; + const unsigned short nDOFsGrid = (const unsigned short)elemInfo[3]; + const unsigned long* conn = elemInfo + 5; /*--- Call the static function GetLocalCornerPointsAllFaces of CPrimalGridFEM to determine the local numbering of the corner points of the faces. ---*/ - CPrimalGridFEM::GetLocalCornerPointsAllFaces(VTK_Type, nPolyGrid, nDOFsGrid, - numFaces, nPointsPerFace, faceConn); + CPrimalGridFEM::GetLocalCornerPointsAllFaces(VTK_Type, nPolyGrid, nDOFsGrid, numFaces, nPointsPerFace, faceConn); /*--- Convert the local values of faceConn to global values. ---*/ - for(unsigned short i=0; i(rank)) { - + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[0].push_back(KindBound); // VTK type. @@ -184,7 +174,7 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { surfaceElementConnectivity[0].push_back(globalElemID); // Global volume element ID. surfaceElementConnectivity[0].push_back(iNode); - surfaceElementConnectivity[0].push_back(iNode+1); + surfaceElementConnectivity[0].push_back(iNode + 1); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[0]; @@ -194,13 +184,11 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { /*--- Loop over all faces on the xMax (= iMax) boundary. ---*/ markerNames[1] = "x_plus"; - for(unsigned long jNode = 0; jNode < mNode-1; ++jNode) { - + for (unsigned long jNode = 0; jNode < mNode - 1; ++jNode) { /*--- Determine the corresponding global element ID and check if it is stored on this rank. ---*/ - const unsigned long globalElemID = jNode*nElemI + nElemI-1; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + const unsigned long globalElemID = jNode * nElemI + nElemI - 1; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[1].push_back(KindBound); // VTK type. @@ -209,8 +197,8 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { surfaceElementConnectivity[1].push_back(jNode); // Global surface element ID. surfaceElementConnectivity[1].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[1].push_back(jNode*nNode + (nNode-1)); - surfaceElementConnectivity[1].push_back((jNode+1)*nNode + (nNode-1)); + surfaceElementConnectivity[1].push_back(jNode * nNode + (nNode - 1)); + surfaceElementConnectivity[1].push_back((jNode + 1) * nNode + (nNode - 1)); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[1]; @@ -220,13 +208,11 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { /*--- Loop over all faces on the yMax (= jMax) boundary. ---*/ markerNames[2] = "y_plus"; - for (unsigned long iNode = 0; iNode < nNode-1; ++iNode) { - - /*--- Determine the corresponding global element ID and check - if it is stored on this rank. ---*/ - const unsigned long globalElemID = (mNode-2)*nElemI + iNode; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + for (unsigned long iNode = 0; iNode < nNode - 1; ++iNode) { + /*--- Determine the corresponding global element ID and check + if it is stored on this rank. ---*/ + const unsigned long globalElemID = (mNode - 2) * nElemI + iNode; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[2].push_back(KindBound); // VTK type. @@ -235,8 +221,8 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { surfaceElementConnectivity[2].push_back(iNode); // Global surface element ID. surfaceElementConnectivity[2].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[2].push_back((mNode-1)*nNode + iNode+1); - surfaceElementConnectivity[2].push_back((mNode-1)*nNode + iNode); + surfaceElementConnectivity[2].push_back((mNode - 1) * nNode + iNode + 1); + surfaceElementConnectivity[2].push_back((mNode - 1) * nNode + iNode); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[2]; @@ -246,13 +232,11 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { /*--- Loop over all faces on the xMin (= iMin) boundary. ---*/ markerNames[3] = "x_minus"; - for(unsigned long jNode = 0; jNode < mNode-1; ++jNode) { - + for (unsigned long jNode = 0; jNode < mNode - 1; ++jNode) { /*--- Determine the corresponding global element ID and check if it is stored on this rank. ---*/ - const unsigned long globalElemID = jNode*nElemI; - if(elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { - + const unsigned long globalElemID = jNode * nElemI; + if (elemPartitioner.GetRankContainingIndex(globalElemID) == static_cast(rank)) { /*--- The corresponding volume element is stored on this rank, hence store the surface element as well. ---*/ surfaceElementConnectivity[3].push_back(KindBound); // VTK type. @@ -261,8 +245,8 @@ void CRectangularMeshReaderFEM::ComputeRectangularSurfaceConnectivity() { surfaceElementConnectivity[3].push_back(jNode); // Global surface element ID. surfaceElementConnectivity[3].push_back(globalElemID); // Global volume element ID. - surfaceElementConnectivity[3].push_back((jNode+1)*nNode); - surfaceElementConnectivity[3].push_back(jNode*nNode); + surfaceElementConnectivity[3].push_back((jNode + 1) * nNode); + surfaceElementConnectivity[3].push_back(jNode * nNode); /*--- Update the number of surface elements for this marker. ---*/ ++numberOfLocalSurfaceElements[3]; diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp index 1802cc9233e..d5087e6d2de 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp @@ -33,8 +33,7 @@ CSU2ASCIIMeshReaderBase::CSU2ASCIIMeshReaderBase(CConfig* val_config, unsigned s : CMeshReaderBase(val_config, val_iZone, val_nZone), myZone(val_iZone), nZones(val_nZone), - meshFilename(config->GetMesh_FileName()) { -} + meshFilename(config->GetMesh_FileName()) {} CSU2ASCIIMeshReaderBase::~CSU2ASCIIMeshReaderBase(void) = default; diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp index ec310aa35f2..f28ef82075b 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp @@ -30,10 +30,8 @@ #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFEM.hpp" #include "../../../include/fem/fem_standard_element.hpp" -CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned short val_iZone, - unsigned short val_nZone) +CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : CSU2ASCIIMeshReaderBase(val_config, val_iZone, val_nZone) { - /* Read the basic metadata and perform some basic error checks. */ ReadMetadata(true, val_config); @@ -53,21 +51,19 @@ CSU2ASCIIMeshReaderFEM::CSU2ASCIIMeshReaderFEM(CConfig *val_config, unsigned sho CSU2ASCIIMeshReaderFEM::~CSU2ASCIIMeshReaderFEM() = default; void CSU2ASCIIMeshReaderFEM::ReadPointCoordinates() { - /*--- Loop over the local elements to determine the global point IDs to be stored on this rank. --*/ unsigned long ind = 0; - for(unsigned long i=0; i> nodeID; localVolumeElementConnectivity.push_back(nodeID); @@ -203,25 +191,20 @@ void CSU2ASCIIMeshReaderFEM::ReadVolumeElementConnectivity() { must be adapted. The reason is that compatability with the original SU2 format is maintained for linear elements, but for the FEM solver the nodes of the elements are stored row-wise. ---*/ - if(nPolyGrid == 1) { - switch( VTK_Type ) { - - case QUADRILATERAL: - swap(localVolumeElementConnectivity[ind+2], - localVolumeElementConnectivity[ind+3]); - break; - - case HEXAHEDRON: - swap(localVolumeElementConnectivity[ind+2], - localVolumeElementConnectivity[ind+3]); - swap(localVolumeElementConnectivity[ind+6], - localVolumeElementConnectivity[ind+7]); - break; - - case PYRAMID: - swap(localVolumeElementConnectivity[ind+2], - localVolumeElementConnectivity[ind+3]); - break; + if (nPolyGrid == 1) { + switch (VTK_Type) { + case QUADRILATERAL: + swap(localVolumeElementConnectivity[ind + 2], localVolumeElementConnectivity[ind + 3]); + break; + + case HEXAHEDRON: + swap(localVolumeElementConnectivity[ind + 2], localVolumeElementConnectivity[ind + 3]); + swap(localVolumeElementConnectivity[ind + 6], localVolumeElementConnectivity[ind + 7]); + break; + + case PYRAMID: + swap(localVolumeElementConnectivity[ind + 2], localVolumeElementConnectivity[ind + 3]); + break; } } } @@ -231,7 +214,6 @@ void CSU2ASCIIMeshReaderFEM::ReadVolumeElementConnectivity() { } void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { - /*--- Determine the vector to hold the faces of the local elements. ---*/ vector localFaces; DetermineFacesVolumeElements(localFaces); @@ -249,58 +231,57 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { /*--- Find the section containing the markers. ---*/ string text_line; - while (getline (mesh_file, text_line)) { - string::size_type position = text_line.find ("NMARK=",0); + while (getline(mesh_file, text_line)) { + string::size_type position = text_line.find("NMARK=", 0); if (position != string::npos) break; } /*--- Loop over the number of boundary markers. ---*/ - for(unsigned long iMarker=0; iMarker connFace(nDOFsGrid); - for(unsigned short j=0; j> connFace[j]; + for (unsigned short j = 0; j < nDOFsGrid; ++j) bound_line >> connFace[j]; /*--- If a linear quadrilateral is used, the node numbering must be adapted. The reason is that compatability with the original SU2 format is maintained for linear elements, but for the FEM solver the nodes of the elements are stored row-wise. ---*/ - if((nPolyGrid == 1) && (VTK_Type == QUADRILATERAL)) - swap(connFace[2], connFace[3]); + if ((nPolyGrid == 1) && (VTK_Type == QUADRILATERAL)) swap(connFace[2], connFace[3]); /*--- Convert the local numbering of thisFace to global numbering and create a unique numbering of corner points. ---*/ - for(unsigned short j=0; j::iterator low; low = lower_bound(localFaces.begin(), localFaces.end(), thisFace); - if(low != localFaces.end()) { - if( !(thisFace < *low) ) { - + if (low != localFaces.end()) { + if (!(thisFace < *low)) { /*--- Update the counter for this boundary marker and store the meta data in surfaceElementConnectivity. ---*/ ++numberOfLocalSurfaceElements[iMarker]; @@ -366,12 +345,12 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { surfaceElementConnectivity[iMarker].push_back(VTK_Type); surfaceElementConnectivity[iMarker].push_back(nPolyGrid); surfaceElementConnectivity[iMarker].push_back(nDOFsGrid); - surfaceElementConnectivity[iMarker].push_back(i); // Global surface elem ID. - surfaceElementConnectivity[iMarker].push_back(low->elemID0); // Global volume elem ID. + surfaceElementConnectivity[iMarker].push_back(i); // Global surface elem ID. + surfaceElementConnectivity[iMarker].push_back(low->elemID0); // Global volume elem ID. /*--- Copy the connectivity to surfaceElementConnectivity. ---*/ - surfaceElementConnectivity[iMarker].insert(surfaceElementConnectivity[iMarker].end(), - connFace.begin(), connFace.end()); + surfaceElementConnectivity[iMarker].insert(surfaceElementConnectivity[iMarker].end(), connFace.begin(), + connFace.end()); } } } diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp index 71fb595e0cb..8403c6af425 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp @@ -28,8 +28,7 @@ #include "../../../include/geometry/meshreader/CSU2ASCIIMeshReaderFVM.hpp" -CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, - unsigned short val_nZone) +CSU2ASCIIMeshReaderFVM::CSU2ASCIIMeshReaderFVM(CConfig* val_config, unsigned short val_iZone, unsigned short val_nZone) : CSU2ASCIIMeshReaderBase(val_config, val_iZone, val_nZone) { actuator_disk = (((config->GetnMarker_ActDiskInlet() != 0) || (config->GetnMarker_ActDiskOutlet() != 0)) && ((config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD) || diff --git a/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp b/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp index 562d6471cde..6b374960f46 100644 --- a/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp +++ b/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp @@ -27,24 +27,19 @@ #include "../../../include/geometry/primal_grid/CPrimalGridBoundFEM.hpp" -CPrimalGridBoundFEM::CPrimalGridBoundFEM(const unsigned long *dataElem) - :CPrimalGrid(true, dataElem[2], 1) -{ - +CPrimalGridBoundFEM::CPrimalGridBoundFEM(const unsigned long* dataElem) : CPrimalGrid(true, dataElem[2], 1) { /*--- Store the meta data for this element. ---*/ - VTK_Type = (unsigned short) dataElem[0]; - nPolyGrid = (unsigned short) dataElem[1]; - nDOFsGrid = (unsigned short) dataElem[2]; + VTK_Type = (unsigned short)dataElem[0]; + nPolyGrid = (unsigned short)dataElem[1]; + nDOFsGrid = (unsigned short)dataElem[2]; boundElemIDGlobal = dataElem[3]; - GlobalIndex_DomainElement = dataElem[4]; + GlobalIndex_DomainElement = dataElem[4]; /*--- Allocate the memory for the global nodes of the element to define the geometry and copy them from val_nodes. ---*/ - for(unsigned short i=0; i Date: Wed, 5 Feb 2025 17:27:11 +0100 Subject: [PATCH 12/15] Fixes from CodeQL --- Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp | 5 +++-- .../src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp | 2 +- Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp | 8 ++++---- 3 files changed, 8 insertions(+), 7 deletions(-) diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp index 1d2c1f22f01..b9208f8ddd6 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -318,7 +318,8 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val_section, const vec case QUADRILATERAL: thisFace.nCornerPoints = 4; - thisFace.cornerPoints[2] = nPolyGrid * nDOFEdgeGrid; + thisFace.cornerPoints[2] = static_cast (nPolyGrid) + * nDOFEdgeGrid; thisFace.cornerPoints[3] = nDOFsGrid - 1; break; @@ -456,7 +457,7 @@ void CCGNSMeshReaderFEM::CommPointCoordinates(void) { /*--- Allocate the memory for a buffer to receive this message and also for the buffer to return to coordinates. ---*/ vector pointRecvBuf(sizeMess); - coorReturnBuf[i].resize(dimension * sizeMess); + coorReturnBuf[i].resize(static_cast(dimension) * sizeMess); /* Receive the message using a blocking receive. */ SU2_MPI::Recv(pointRecvBuf.data(), sizeMess, MPI_UNSIGNED_LONG, source, rank, SU2_MPI::GetComm(), &status); diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp index d5087e6d2de..d8c524eff4c 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderBase.cpp @@ -393,7 +393,7 @@ void CSU2ASCIIMeshReaderBase::ReadSurfaceElementConnectivity(const bool single_p if (text_line.find("NMARK=", 0) == string::npos) continue; } - for (unsigned short iMarker = 0; iMarker < numberOfMarkers; ++iMarker) { + for (unsigned long iMarker = 0; iMarker < numberOfMarkers; ++iMarker) { getline(mesh_file, text_line); text_line.erase(0, 11); string::size_type position; diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp index f28ef82075b..e0ef76294a7 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp @@ -247,10 +247,9 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { /*--- Extract the marker name. Remove spaces returns and tabs and store the name in markerNames. ---*/ text_line.erase(0, 11); - string::size_type position; for (unsigned short iChar = 0; iChar < 20; iChar++) { - position = text_line.find(" ", 0); + auto position = text_line.find(" ", 0); if (position != string::npos) text_line.erase(position, 1); position = text_line.find("\r", 0); if (position != string::npos) text_line.erase(position, 1); @@ -262,7 +261,7 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { /*--- Find the section containing the number of surface elements for this marker and determine this number. ---*/ while (getline(mesh_file, text_line)) { - string::size_type position = text_line.find("MARKER_ELEMS=", 0); + auto position = text_line.find("MARKER_ELEMS=", 0); if (position != string::npos) break; } @@ -307,7 +306,8 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { case QUADRILATERAL: nDOFsGrid = nDOFEdgeGrid * nDOFEdgeGrid; thisFace.nCornerPoints = 4; - thisFace.cornerPoints[2] = nPolyGrid * nDOFEdgeGrid; + thisFace.cornerPoints[2] = static_cast(nPolyGrid) + * nDOFEdgeGrid; thisFace.cornerPoints[3] = nDOFsGrid - 1; break; From 6a659d7a078c791e700c518fe7da1863ed4aca3c Mon Sep 17 00:00:00 2001 From: vdweide Date: Wed, 5 Feb 2025 17:29:29 +0100 Subject: [PATCH 13/15] Result of running pre-commit --- Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp | 3 +-- Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp index b9208f8ddd6..3757a278478 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -318,8 +318,7 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val_section, const vec case QUADRILATERAL: thisFace.nCornerPoints = 4; - thisFace.cornerPoints[2] = static_cast (nPolyGrid) - * nDOFEdgeGrid; + thisFace.cornerPoints[2] = static_cast(nPolyGrid) * nDOFEdgeGrid; thisFace.cornerPoints[3] = nDOFsGrid - 1; break; diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp index e0ef76294a7..78dc46b3f10 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFEM.cpp @@ -306,8 +306,7 @@ void CSU2ASCIIMeshReaderFEM::ReadSurfaceElementConnectivity() { case QUADRILATERAL: nDOFsGrid = nDOFEdgeGrid * nDOFEdgeGrid; thisFace.nCornerPoints = 4; - thisFace.cornerPoints[2] = static_cast(nPolyGrid) - * nDOFEdgeGrid; + thisFace.cornerPoints[2] = static_cast(nPolyGrid) * nDOFEdgeGrid; thisFace.cornerPoints[3] = nDOFsGrid - 1; break; From 53207abb9c032466787c1185c1e8832fe3335128 Mon Sep 17 00:00:00 2001 From: vdweide Date: Thu, 6 Feb 2025 09:57:34 +0100 Subject: [PATCH 14/15] Replaced the C-style cast by static_cast --- Common/src/fem/fem_geometry_structure.cpp | 36 +++++----- Common/src/fem/fem_standard_element.cpp | 8 +-- .../src/fem/geometry_structure_fem_part.cpp | 14 ++-- Common/src/geometry/CGeometry.cpp | 16 ++--- Common/src/geometry/CPhysicalGeometry.cpp | 70 +++++++++---------- .../geometry/meshreader/CBoxMeshReaderFVM.cpp | 6 +- .../meshreader/CCGNSMeshReaderBase.cpp | 2 +- .../meshreader/CCGNSMeshReaderFEM.cpp | 6 +- .../meshreader/CCGNSMeshReaderFVM.cpp | 24 +++---- .../meshreader/CRectangularMeshReaderFVM.cpp | 6 +- .../meshreader/CSU2ASCIIMeshReaderFVM.cpp | 24 +++---- .../primal_grid/CPrimalGridBoundFEM.cpp | 6 +- .../geometry/primal_grid/CPrimalGridFEM.cpp | 8 +-- 13 files changed, 113 insertions(+), 113 deletions(-) diff --git a/Common/src/fem/fem_geometry_structure.cpp b/Common/src/fem/fem_geometry_structure.cpp index e5580de752e..7a0b5177129 100644 --- a/Common/src/fem/fem_geometry_structure.cpp +++ b/Common/src/fem/fem_geometry_structure.cpp @@ -267,14 +267,14 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { map rankToIndCommBuf; for (int i = 0; i < size; ++i) { if (sendToRank[i]) { - int ind = (int)rankToIndCommBuf.size(); + int ind = static_cast(rankToIndCommBuf.size()); rankToIndCommBuf[i] = ind; } } /*--- Definition of the communication buffers, used to send the element data to the correct ranks. ---*/ - int nRankSend = (int)rankToIndCommBuf.size(); + int nRankSend = static_cast(rankToIndCommBuf.size()); vector > shortSendBuf(nRankSend, vector(0)); vector > longSendBuf(nRankSend, vector(0)); vector > doubleSendBuf(nRankSend, vector(0)); @@ -294,7 +294,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /*--- Loop over the local elements to fill the communication buffers with element data. ---*/ for (unsigned long i = 0; i < geometry->GetnElem(); ++i) { - int ind = (int)geometry->elem[i]->GetColor(); + int ind = static_cast(geometry->elem[i]->GetColor()); map::const_iterator MI = rankToIndCommBuf.find(ind); ind = MI->second; @@ -385,7 +385,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /* Determine to which rank this boundary element must be sent. That is the same as its corresponding domain element. Update the corresponding index in longSendBuf. */ - int ind = (int)geometry->elem[elemID]->GetColor(); + int ind = static_cast(geometry->elem[elemID]->GetColor()); const auto MI = rankToIndCommBuf.find(ind); ind = MI->second; @@ -566,8 +566,8 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { the elements with constant and non-constant Jacobians are considered the same. */ if (JacConstant) { - const auto orderExactStraight = (unsigned short)ceil(nPolySol * config->GetQuadrature_Factor_Straight()); - const auto orderExactCurved = (unsigned short)ceil(nPolySol * config->GetQuadrature_Factor_Curved()); + const auto orderExactStraight = static_cast(ceil(nPolySol * config->GetQuadrature_Factor_Straight())); + const auto orderExactCurved = static_cast(ceil(nPolySol * config->GetQuadrature_Factor_Curved())); if (orderExactStraight == orderExactCurved) JacConstant = false; } @@ -691,14 +691,14 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { rankToIndCommBuf.clear(); for (int i = 0; i < size; ++i) { if (sendToRank[i]) { - int ind = (int)rankToIndCommBuf.size(); + int ind = static_cast(rankToIndCommBuf.size()); rankToIndCommBuf[i] = ind; } } /* Resize the first index of the long send buffers for the communication of the halo data. */ - nRankSend = (int)rankToIndCommBuf.size(); + nRankSend = static_cast(rankToIndCommBuf.size()); longSendBuf.resize(nRankSend); /* Determine the number of ranks, from which this rank will receive elements. */ @@ -717,7 +717,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { if (*low > haloElements[i].long0) --ind; /* Convert this rank to the index in the send buffer. */ - MI = rankToIndCommBuf.find((int)ind); + MI = rankToIndCommBuf.find(static_cast(ind)); ind = MI->second; /* Store the global element ID and the periodic index in the long buffer. @@ -911,12 +911,12 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { for (int i = 0; i < size; ++i) { if (nHaloElemPerRank[i + 1] > nHaloElemPerRank[i]) { sendToRank[i] = 1; - int ind = (int)rankToIndCommBuf.size(); + int ind = static_cast(rankToIndCommBuf.size()); rankToIndCommBuf[i] = ind; } } - nRankSend = (int)rankToIndCommBuf.size(); + nRankSend = static_cast(rankToIndCommBuf.size()); /* Store the value of nRankSend for later use. */ const int nRankSendHaloInfo = nRankSend; @@ -1179,7 +1179,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /*--- Create the graph of local elements. The halo elements are ignored. ---*/ vector > neighElem(nVolElemOwned, vector(0)); - nRankRecv = (int)longRecvBuf.size(); + nRankRecv = static_cast(longRecvBuf.size()); for (int i = 0; i < nRankRecv; ++i) { unsigned long indL = 1, indS = 0; for (long j = 0; j < longRecvBuf[i][0]; ++j) { @@ -1452,7 +1452,7 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { /*--- Resize the first index of the send buffers to nRankRecv, because this number of messages must be sent back to the sending ranks with halo information. ---*/ - nRankRecv = (int)longSecondRecvBuf.size(); + nRankRecv = static_cast(longSecondRecvBuf.size()); shortSendBuf.resize(nRankRecv); longSendBuf.resize(nRankRecv); doubleSendBuf.resize(nRankRecv); @@ -2455,12 +2455,12 @@ void CMeshFEM_DG::CreateFaces(CConfig* config) { is set to false. Hence it is only needed to carry out this check for faces with a constant Jacobian. This is done to reduce the number of standard elements. */ if (thisFace.JacFaceIsConsideredConstant) { - auto orderExactStraight = (unsigned short)ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Straight()); - auto orderExactCurved = (unsigned short)ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Curved()); + auto orderExactStraight = static_cast(ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Straight())); + auto orderExactCurved = static_cast(ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Curved())); if (orderExactStraight == orderExactCurved) { - orderExactStraight = (unsigned short)ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Straight()); - orderExactCurved = (unsigned short)ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Curved()); + orderExactStraight = static_cast(ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Straight())); + orderExactCurved = static_cast(ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Curved())); if (orderExactStraight == orderExactCurved) thisFace.JacFaceIsConsideredConstant = false; } } @@ -3159,7 +3159,7 @@ void CMeshFEM_DG::SetSendReceive(const CConfig* config) { map rankToIndRecvBuf; for (int i = 0; i < size; ++i) { if (recvFromRank[i]) { - int ind = (int)rankToIndRecvBuf.size(); + int ind = static_cast(rankToIndRecvBuf.size()); rankToIndRecvBuf[i] = ind; } } diff --git a/Common/src/fem/fem_standard_element.cpp b/Common/src/fem/fem_standard_element.cpp index b24c7cacfaf..ab8e537ad9c 100644 --- a/Common/src/fem/fem_standard_element.cpp +++ b/Common/src/fem/fem_standard_element.cpp @@ -186,9 +186,9 @@ CFEMStandardElementBase::CFEMStandardElementBase(unsigned short val_VTK_Type, un orderExact = val_orderExact; } else { if (constJacobian) - orderExact = (unsigned short)ceil(val_nPoly * config->GetQuadrature_Factor_Straight()); + orderExact = static_cast(ceil(val_nPoly * config->GetQuadrature_Factor_Straight())); else - orderExact = (unsigned short)ceil(val_nPoly * config->GetQuadrature_Factor_Curved()); + orderExact = static_cast(ceil(val_nPoly * config->GetQuadrature_Factor_Curved())); } /*--- Determine the integration points. This depends on the element type. ---*/ @@ -903,7 +903,7 @@ void CFEMStandardElementBase::SubConnForPlottingLine(const unsigned short nPoly, /*--- Determine the local subconnectivity of the line element used for plotting purposes. This is rather trivial, because the line element is subdivided into nPoly linear line elements. ---*/ - unsigned short nnPoly = max(nPoly, (unsigned short)1); + unsigned short nnPoly = max(nPoly, static_cast(1)); for (unsigned short i = 0; i < nnPoly; ++i) { subConn.push_back(i); subConn.push_back(i + 1); @@ -916,7 +916,7 @@ void CFEMStandardElementBase::SubConnForPlottingQuadrilateral(const unsigned sho plotting purposes. Note that the connectivity of the linear subelements obey the VTK connectivity rule of a quadrilateral, which is different from the connectivity for the high order quadrilateral. ---*/ - unsigned short nnPoly = max(nPoly, (unsigned short)1); + unsigned short nnPoly = max(nPoly, static_cast(1)); for (unsigned short j = 0; j < nnPoly; ++j) { unsigned short jj = j * (nnPoly + 1); for (unsigned short i = 0; i < nnPoly; ++i) { diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index 1babb698f7d..a0309bf2233 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -609,7 +609,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { the points that occur in the faces of localFacesComm. ---*/ vector facePointsProc(size + 1, 0); unsigned long total_point_accounted = 0; - for (unsigned long i = 1; i <= (unsigned long)size; ++i) { + for (unsigned long i = 1; i <= static_cast(size); ++i) { facePointsProc[i] = maxPointID / size; total_point_accounted += facePointsProc[i]; } @@ -617,7 +617,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { unsigned long rem_point = maxPointID - total_point_accounted; for (unsigned long i = 1; i <= rem_point; ++i) ++facePointsProc[i]; - for (unsigned long i = 0; i < (unsigned long)size; ++i) facePointsProc[i + 1] += facePointsProc[i]; + for (unsigned long i = 0; i < static_cast(size); ++i) facePointsProc[i + 1] += facePointsProc[i]; /*--- Determine the number of faces that has to be sent to each rank. Note that the rank is stored in elemID1, such that the search @@ -637,7 +637,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { vector sendBufFace(9 * nFacesLocComm); vector counter(size); counter[0] = 0; - for (unsigned long i = 1; i < (unsigned long)size; ++i) counter[i] = counter[i - 1] + 9 * nFacesComm[i - 1]; + for (unsigned long i = 1; i < static_cast(size); ++i) counter[i] = counter[i - 1] + 9 * nFacesComm[i - 1]; for (unsigned long i = 0; i < nFacesLocComm; ++i) { unsigned long rankFace = localFacesComm[i].elemID1; @@ -657,7 +657,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { /*--- Determine the number of ranks from which I receive a message. */ unsigned long nMessSend = 0; - for (unsigned long i = 0; i < (unsigned long)size; ++i) { + for (unsigned long i = 0; i < static_cast(size); ++i) { if (nFacesComm[i]) { counter[i] = 1; ++nMessSend; @@ -674,7 +674,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { nMessSend = 0; unsigned long indSend = 0; - for (unsigned long i = 0; i < (unsigned long)size; ++i) { + for (unsigned long i = 0; i < static_cast(size); ++i) { if (nFacesComm[i]) { unsigned long count = 9 * nFacesComm[i]; SU2_MPI::Isend(&sendBufFace[indSend], count, MPI_UNSIGNED_LONG, i, i, SU2_MPI::GetComm(), &commReqs[nMessSend]); @@ -792,7 +792,7 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { sizeMess /= 9; unsigned long jj = 0; - for (unsigned long j = 0; j < (unsigned long)sizeMess; ++j, jj += 9) { + for (unsigned long j = 0; j < static_cast(sizeMess); ++j, jj += 9) { CFaceOfElement thisFace; thisFace.nCornerPoints = recvBuf[jj]; thisFace.cornerPoints[0] = recvBuf[jj + 1]; @@ -2240,7 +2240,7 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig* config) { carried out for each rank and store them in such a way that the info can be used directly in Allgatherv. */ vector recvCounts(size), displs(size); - int nLocalSearchPoints = (int)markerIDGlobalSearch.size(); + int nLocalSearchPoints = static_cast(markerIDGlobalSearch.size()); SU2_MPI::Allgather(&nLocalSearchPoints, 1, MPI_INT, recvCounts.data(), 1, MPI_INT, SU2_MPI::GetComm()); displs[0] = 0; diff --git a/Common/src/geometry/CGeometry.cpp b/Common/src/geometry/CGeometry.cpp index cf1a6948c5f..e771960b638 100644 --- a/Common/src/geometry/CGeometry.cpp +++ b/Common/src/geometry/CGeometry.cpp @@ -183,8 +183,8 @@ void CGeometry::PreprocessP2PComms(CGeometry* geometry, CConfig* config) { /*--- If we have not visited this element yet, increment our number of elements that must be sent to a particular proc. ---*/ - if ((nPoint_Flag[iRank] != (int)iMarker)) { - nPoint_Flag[iRank] = (int)iMarker; + if ((nPoint_Flag[iRank] != static_cast(iMarker))) { + nPoint_Flag[iRank] = static_cast(iMarker); nPoint_Send_All[iRank + 1] += nVertexS; } } @@ -819,13 +819,13 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) { /*--- Get the rank that holds the matching periodic point on the other marker in the periodic pair. ---*/ - iRank = (int)geometry->vertex[iMarker][iVertex]->GetDonorProcessor(); + iRank = static_cast(geometry->vertex[iMarker][iVertex]->GetDonorProcessor()); /*--- If we have not visited this point last, increment our number of points that must be sent to a particular proc. ---*/ - if ((nPoint_Flag[iRank] != (int)iPoint)) { - nPoint_Flag[iRank] = (int)iPoint; + if ((nPoint_Flag[iRank] != static_cast(iPoint))) { + nPoint_Flag[iRank] = static_cast(iPoint); nPoint_Send_All[iRank + 1] += 1; } } @@ -962,7 +962,7 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) { /*--- Get the rank that holds the matching periodic point on the other marker in the periodic pair. ---*/ - iRank = (int)geometry->vertex[iMarker][iVertex]->GetDonorProcessor(); + iRank = static_cast(geometry->vertex[iMarker][iVertex]->GetDonorProcessor()); /*--- If the rank for the current periodic point matches the rank of the current send message, then store the local point @@ -971,11 +971,11 @@ void CGeometry::PreprocessPeriodicComms(CGeometry* geometry, CConfig* config) { if (iRank == Neighbors_PeriodicSend[iSend]) { Local_Point_PeriodicSend[ii] = iPoint; - Local_Marker_PeriodicSend[ii] = (unsigned long)iMarker; + Local_Marker_PeriodicSend[ii] = static_cast(iMarker); jj = ii * nPackets; idSend[jj] = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); jj++; - idSend[jj] = (unsigned long)iPeriodic; + idSend[jj] = static_cast(iPeriodic); ii++; } } diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 20c2b247510..1c53744b191 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -547,8 +547,8 @@ void CPhysicalGeometry::DistributeColoring(const CConfig* config, CGeometry* geo /*--- If we have not visited this node yet, increment our number of points that must be sent to a particular proc. ---*/ - if (nPoint_Flag[iProcessor] != (int)iPoint) { - nPoint_Flag[iProcessor] = (int)iPoint; + if (nPoint_Flag[iProcessor] != static_cast(iPoint)) { + nPoint_Flag[iProcessor] = static_cast(iPoint); nPoint_Send[iProcessor + 1]++; } } @@ -607,8 +607,8 @@ void CPhysicalGeometry::DistributeColoring(const CConfig* config, CGeometry* geo /*--- If we have not visited this node yet, increment our counters and load up the global ID and color. ---*/ - if (nPoint_Flag[iProcessor] != (int)iPoint) { - nPoint_Flag[iProcessor] = (int)iPoint; + if (nPoint_Flag[iProcessor] != static_cast(iPoint)) { + nPoint_Flag[iProcessor] = static_cast(iPoint); unsigned long nn = index[iProcessor]; /*--- Load the data values. ---*/ @@ -780,8 +780,8 @@ void CPhysicalGeometry::DistributeVolumeConnectivity(const CConfig* config, CGeo /*--- If we have not visited this element yet, increment our number of elements that must be sent to a particular proc. ---*/ - if ((nElem_Flag[iProcessor] != (int)iElem)) { - nElem_Flag[iProcessor] = (int)iElem; + if ((nElem_Flag[iProcessor] != static_cast(iElem))) { + nElem_Flag[iProcessor] = static_cast(iElem); nElem_Send[iProcessor + 1]++; } } @@ -847,8 +847,8 @@ void CPhysicalGeometry::DistributeVolumeConnectivity(const CConfig* config, CGeo /*--- Load connectivity and IDs into the buffer for sending ---*/ - if (nElem_Flag[iProcessor] != (int)iElem) { - nElem_Flag[iProcessor] = (int)iElem; + if (nElem_Flag[iProcessor] != static_cast(iElem)) { + nElem_Flag[iProcessor] = static_cast(iElem); unsigned long nn = index[iProcessor]; unsigned long mm = idIndex[iProcessor]; @@ -1071,8 +1071,8 @@ void CPhysicalGeometry::DistributePoints(const CConfig* config, CGeometry* geome /*--- If we have not visited this node yet, increment our number of points that must be sent to a particular proc. ---*/ - if (nPoint_Flag[iProcessor] != (int)iPoint) { - nPoint_Flag[iProcessor] = (int)iPoint; + if (nPoint_Flag[iProcessor] != static_cast(iPoint)) { + nPoint_Flag[iProcessor] = static_cast(iPoint); nPoint_Send[iProcessor + 1]++; } } @@ -1140,8 +1140,8 @@ void CPhysicalGeometry::DistributePoints(const CConfig* config, CGeometry* geome /*--- If we have not visited this node yet, increment our counters and load up the colors, ids, and coords. ---*/ - if (nPoint_Flag[iProcessor] != (int)iPoint) { - nPoint_Flag[iProcessor] = (int)iPoint; + if (nPoint_Flag[iProcessor] != static_cast(iPoint)) { + nPoint_Flag[iProcessor] = static_cast(iPoint); unsigned long nn = index[iProcessor]; /*--- Load the global ID, color, and coordinate values. ---*/ @@ -1248,7 +1248,7 @@ void CPhysicalGeometry::DistributePoints(const CConfig* config, CGeometry* geome Local_Points[iRecv] = idRecv[iRecv]; Local_Colors[iRecv] = colorRecv[iRecv]; for (iDim = 0; iDim < nDim; iDim++) Local_Coords[iRecv * nDim + iDim] = coordRecv[iRecv * nDim + iDim]; - if (Local_Colors[iRecv] == (unsigned long)rank) + if (Local_Colors[iRecv] == static_cast(rank)) nLocal_PointDomain++; else nLocal_PointGhost++; @@ -1359,8 +1359,8 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig* config, CGeometry* /*--- If we have not visited this element yet, increment our number of elements that must be sent to a particular proc. ---*/ - if ((nElem_Flag[iProcessor] != (int)iElem)) { - nElem_Flag[iProcessor] = (int)iElem; + if ((nElem_Flag[iProcessor] != static_cast(iElem))) { + nElem_Flag[iProcessor] = static_cast(iElem); nElem_Send[iProcessor + 1]++; } } @@ -1440,8 +1440,8 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig* config, CGeometry* /*--- Load connectivity into the buffer for sending ---*/ - if ((nElem_Flag[iProcessor] != (int)iElem)) { - nElem_Flag[iProcessor] = (int)iElem; + if ((nElem_Flag[iProcessor] != static_cast(iElem))) { + nElem_Flag[iProcessor] = static_cast(iElem); unsigned long nn = index[iProcessor]; unsigned long mm = markerIndex[iProcessor]; @@ -1712,8 +1712,8 @@ void CPhysicalGeometry::DistributeSurfaceConnectivity(CConfig* config, CGeometry /*--- If we have not visited this element yet, increment our number of elements that must be sent to a particular proc. ---*/ - if ((nElem_Flag[iProcessor] != (int)iElem)) { - nElem_Flag[iProcessor] = (int)iElem; + if ((nElem_Flag[iProcessor] != static_cast(iElem))) { + nElem_Flag[iProcessor] = static_cast(iElem); nElem_Send[iProcessor + 1]++; } } @@ -1781,8 +1781,8 @@ void CPhysicalGeometry::DistributeSurfaceConnectivity(CConfig* config, CGeometry /*--- If we have not visited this element yet, load up the data for sending. ---*/ - if (nElem_Flag[iProcessor] != (int)iElem) { - nElem_Flag[iProcessor] = (int)iElem; + if (nElem_Flag[iProcessor] != static_cast(iElem)) { + nElem_Flag[iProcessor] = static_cast(iElem); unsigned long nn = index[iProcessor]; unsigned long mm = markerIndex[iProcessor]; @@ -1990,7 +1990,7 @@ void CPhysicalGeometry::DistributeMarkerTags(CConfig* config, CGeometry* geometr /*--- Broadcast the string names of the variables. ---*/ - SU2_MPI::Bcast(mpi_str_buf, (int)nMarker_Global * MAX_STRING_SIZE, MPI_CHAR, MASTER_NODE, SU2_MPI::GetComm()); + SU2_MPI::Bcast(mpi_str_buf, static_cast(nMarker_Global) * MAX_STRING_SIZE, MPI_CHAR, MASTER_NODE, SU2_MPI::GetComm()); /*--- Now parse the string names and load into our marker tag vector. We also need to set the values of all markers into the config. ---*/ @@ -2042,7 +2042,7 @@ void CPhysicalGeometry::LoadPoints(CConfig* config, CGeometry* geometry) { for (iPoint = 0; iPoint < nPoint; iPoint++) { /*--- Set the starting point to the correct counter for this point. ---*/ - if (Local_Colors[iPoint] == (unsigned long)rank) { + if (Local_Colors[iPoint] == static_cast(rank)) { if (Local_Points[iPoint] < geometry->GetGlobal_nPointDomain()) jPoint = iOwned; else @@ -2066,7 +2066,7 @@ void CPhysicalGeometry::LoadPoints(CConfig* config, CGeometry* geometry) { /*--- Increment the correct counter before moving to the next point. ---*/ - if (Local_Colors[iPoint] == (unsigned long)rank) { + if (Local_Colors[iPoint] == static_cast(rank)) { if (Local_Points[iPoint] < geometry->GetGlobal_nPointDomain()) iOwned++; else @@ -2875,7 +2875,7 @@ unsigned long CPhysicalGeometry::GetLinearPartition(unsigned long val_global_ind /*--- Guard against going over size. ---*/ - if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size - 1; + if (iProcessor >= static_cast(size)) iProcessor = static_cast(size) - 1; /*--- Move up or down until we find the processor. ---*/ @@ -2990,7 +2990,7 @@ void CPhysicalGeometry::SetSendReceive(const CConfig* config) { iPoint = elem[iElem]->GetNode(iNode); iDomain = nodes->GetColor(iPoint); - if (iDomain == (unsigned long)rank) { + if (iDomain == static_cast(rank)) { for (jNode = 0; jNode < elem[iElem]->GetnNodes(); jNode++) { jPoint = elem[iElem]->GetNode(jNode); jDomain = nodes->GetColor(jPoint); @@ -3717,11 +3717,11 @@ void CPhysicalGeometry::LoadUnpartitionedSurfaceElements(CConfig* config, CMeshR /*--- Not a mixed section. We already know the element type, which is stored ---*/ - vtk_type = (int)connElems[jElem * SU2_CONN_SIZE + 1]; + vtk_type = static_cast(connElems[jElem * SU2_CONN_SIZE + 1]); /*--- Store the loop size more easily. ---*/ - npe = (int)(SU2_CONN_SIZE - SU2_CONN_SKIP); + npe = static_cast(SU2_CONN_SIZE - SU2_CONN_SKIP); /*--- Store the nodes for this element more clearly. ---*/ @@ -5097,7 +5097,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig* config, unsigned short val_iZone if (config->GetMarker_All_TurbomachineryFlag(iMarker) == marker_flag) { /*--- compute the amount of vertexes for each span-wise section to initialize the CTurboVertex pointers and * auxiliary pointers ---*/ - for (iVertex = 0; (unsigned long)iVertex < nVertex[iMarker]; iVertex++) { + for (iVertex = 0; static_cast(iVertex) < nVertex[iMarker]; iVertex++) { iPoint = vertex[iMarker][iVertex]->GetNode(); if (nDim == 3) { dist = 10E+06; @@ -5197,7 +5197,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig* config, unsigned short val_iZone } /*--- store the vertexes in a ordered manner in span-wise directions but not yet ordered pitch-wise ---*/ - for (iVertex = 0; (unsigned long)iVertex < nVertex[iMarker]; iVertex++) { + for (iVertex = 0; static_cast(iVertex) < nVertex[iMarker]; iVertex++) { iPoint = vertex[iMarker][iVertex]->GetNode(); if (nDim == 3) { dist = 10E+06; @@ -5523,7 +5523,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig* config, unsigned short val_iZone SetnVertexSpanMax(marker_flag, nVert); } /*--- for all the processor should be known the amount of total turbovertex per span ---*/ - nTotVertex_gb[iSpan] = (int)nVert; + nTotVertex_gb[iSpan] = static_cast(nVert); for (iMarker = 0; iMarker < nMarker; iMarker++) { for (iMarkerTP = 1; iMarkerTP < config->GetnMarker_Turbomachinery() + 1; iMarkerTP++) { @@ -8275,7 +8275,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig* config) { /*--- First, read the number of variables and points. ---*/ ret = fread(Restart_Vars, sizeof(int), nRestart_Vars, fhw); - if (ret != (unsigned long)nRestart_Vars) { + if (ret != static_cast(nRestart_Vars)) { SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION); } @@ -8302,7 +8302,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig* config) { config->fields.push_back("Point_ID"); for (iVar = 0; iVar < nFields; iVar++) { ret = fread(str_buf, sizeof(char), CGNS_STRING_SIZE, fhw); - if (ret != (unsigned long)CGNS_STRING_SIZE) { + if (ret != static_cast(CGNS_STRING_SIZE)) { SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION); } config->fields.push_back(str_buf); @@ -8315,7 +8315,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig* config) { /*--- Read in the data for the restart at all local points. ---*/ ret = fread(Restart_Data, sizeof(passivedouble), nFields * GetnPointDomain(), fhw); - if (ret != (unsigned long)nFields * GetnPointDomain()) { + if (ret != static_cast(nFields) * GetnPointDomain()) { SU2_MPI::Error("Error reading restart file.", CURRENT_FUNCTION); } @@ -8410,7 +8410,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig* config) { config->fields.emplace_back("Point_ID"); for (iVar = 0; iVar < nFields; iVar++) { index = iVar * CGNS_STRING_SIZE; - for (iChar = 0; iChar < (unsigned long)CGNS_STRING_SIZE; iChar++) { + for (iChar = 0; iChar < static_cast(CGNS_STRING_SIZE); iChar++) { str_buf[iChar] = mpi_str_buf[index + iChar]; } field_buf.append(str_buf); diff --git a/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp index 962e32e478d..e2c0f52c3b1 100644 --- a/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CBoxMeshReaderFVM.cpp @@ -74,7 +74,7 @@ void CBoxMeshReaderFVM::ComputeBoxPointCoordinates() { /* Determine number of local points */ for (unsigned long globalIndex = 0; globalIndex < numberOfGlobalPoints; globalIndex++) { - if ((int)pointPartitioner.GetRankContainingIndex(globalIndex) == rank) { + if (static_cast(pointPartitioner.GetRankContainingIndex(globalIndex)) == rank) { numberOfLocalPoints++; } } @@ -88,7 +88,7 @@ void CBoxMeshReaderFVM::ComputeBoxPointCoordinates() { for (unsigned long kNode = 0; kNode < pNode; kNode++) { for (unsigned long jNode = 0; jNode < mNode; jNode++) { for (unsigned long iNode = 0; iNode < nNode; iNode++) { - if ((int)pointPartitioner.GetRankContainingIndex(globalIndex) == rank) { + if (static_cast(pointPartitioner.GetRankContainingIndex(globalIndex)) == rank) { /* Store the coordinates more clearly. */ const passivedouble x = SU2_TYPE::GetValue(Lx * ((su2double)iNode) / ((su2double)(nNode - 1)) + Ox); const passivedouble y = SU2_TYPE::GetValue(Ly * ((su2double)jNode) / ((su2double)(mNode - 1)) + Oy); @@ -133,7 +133,7 @@ void CBoxMeshReaderFVM::ComputeBoxVolumeConnectivity() { /* Check whether any of the points is in our linear partition. */ bool isOwned = false; for (unsigned short i = 0; i < N_POINTS_HEXAHEDRON; i++) { - if ((int)pointPartitioner.GetRankContainingIndex(connectivity[i]) == rank) { + if (static_cast(pointPartitioner.GetRankContainingIndex(connectivity[i])) == rank) { isOwned = true; } } diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp index 53697f65958..042ef3f9111 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderBase.cpp @@ -102,7 +102,7 @@ void CCGNSMeshReaderBase::ReadCGNSDatabaseMetadata() { /*--- Set the number of dimensions baed on cell_dim. ---*/ - dimension = (unsigned short)cell_dim; + dimension = static_cast(cell_dim); } void CCGNSMeshReaderBase::ReadCGNSZoneMetadata() { diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp index 3757a278478..32cb790291c 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFEM.cpp @@ -294,9 +294,9 @@ void CCGNSMeshReaderFEM::ReadCGNSSurfaceSection(const int val_section, const vec /*--- Easier storage of the VTK type, polynomial degree and number of DOFs of the surface element. ---*/ - const unsigned short VTK_Type = (unsigned short)connSU2[0]; - const unsigned short nPolyGrid = (unsigned short)connSU2[1]; - const unsigned short nDOFsGrid = (unsigned short)connSU2[3]; + const unsigned short VTK_Type = static_cast(connSU2[0]); + const unsigned short nPolyGrid = static_cast(connSU2[1]); + const unsigned short nDOFsGrid = static_cast(connSU2[3]); /*--- Make a distinction between the possible element surface types and determine the corner points in local numbering of the element. ---*/ diff --git a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp index 45025e6b4bf..2c0dabc8236 100644 --- a/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CCGNSMeshReaderFVM.cpp @@ -244,7 +244,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { entry if this is a mixed element section. ---*/ if (isMixed) counterCGNS++; - for (iNode = 0; iNode < (unsigned long)nPoinPerElem[iElem]; iNode++) { + for (iNode = 0; iNode < static_cast(nPoinPerElem[iElem]); iNode++) { connElemTemp[nn] = connElemCGNS[counterCGNS + iNode] - 1; nn++; } @@ -281,7 +281,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { CLinearPartitioner pointPartitioner(numberOfGlobalPoints, 0); for (iElem = 0; iElem < nElems[val_section]; iElem++) { - for (iNode = 0; iNode < (unsigned long)nPoinPerElem[iElem]; iNode++) { + for (iNode = 0; iNode < static_cast(nPoinPerElem[iElem]); iNode++) { /*--- Get the index of the current point. ---*/ iPoint = connElemTemp[iElem * SU2_CONN_SIZE + SU2_CONN_SKIP + iNode]; @@ -293,7 +293,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { /*--- If we have not visited this element yet, increment our number of elements that must be sent to a particular proc. ---*/ - if ((nElem_Flag[iProcessor] != (int)iElem)) { + if ((nElem_Flag[iProcessor] != static_cast(iElem))) { nElem_Flag[iProcessor] = iElem; nElem_Send[iProcessor + 1]++; } @@ -329,7 +329,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { + 2 extra values for the ID and VTK. ---*/ unsigned long *connSend = nullptr, iSend = 0; - unsigned long sendSize = (unsigned long)SU2_CONN_SIZE * nElem_Send[size]; + unsigned long sendSize = static_cast(SU2_CONN_SIZE) * nElem_Send[size]; connSend = new unsigned long[sendSize]; for (iSend = 0; iSend < sendSize; iSend++) connSend[iSend] = 0; @@ -342,8 +342,8 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { /*--- Loop through our elements and load the elems and their additional data that we will send to the other procs. ---*/ - for (iElem = 0; iElem < (unsigned long)nElems[val_section]; iElem++) { - for (iNode = 0; iNode < (unsigned long)nPoinPerElem[iElem]; iNode++) { + for (iElem = 0; iElem < static_cast(nElems[val_section]); iElem++) { + for (iNode = 0; iNode < static_cast(nPoinPerElem[iElem]); iNode++) { /*--- Get the index of the current point. ---*/ iPoint = connElemTemp[iElem * SU2_CONN_SIZE + SU2_CONN_SKIP + iNode]; @@ -354,7 +354,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { /*--- Load connectivity into the buffer for sending ---*/ - if (nElem_Flag[iProcessor] != (int)iElem) { + if (nElem_Flag[iProcessor] != static_cast(iElem)) { nElem_Flag[iProcessor] = iElem; unsigned long nn = index[iProcessor]; @@ -388,7 +388,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { directly copy our own data later. ---*/ unsigned long *connRecv = nullptr, iRecv = 0; - unsigned long recvSize = (unsigned long)SU2_CONN_SIZE * nElem_Recv[size]; + unsigned long recvSize = static_cast(SU2_CONN_SIZE) * nElem_Recv[size]; connRecv = new unsigned long[recvSize]; for (iRecv = 0; iRecv < recvSize; iRecv++) connRecv[iRecv] = 0; @@ -430,7 +430,7 @@ void CCGNSMeshReaderFVM::ReadCGNSVolumeSection(int val_section) { if (nElem_Recv[size] > 0) { connElems[val_section].resize(nElem_Recv[size] * SU2_CONN_SIZE, 0); unsigned long count = 0; - for (iElem = 0; iElem < (unsigned long)nElem_Recv[size]; iElem++) { + for (iElem = 0; iElem < static_cast(nElem_Recv[size]); iElem++) { for (iNode = 0; iNode < SU2_CONN_SIZE; iNode++) { unsigned long nn = iElem * SU2_CONN_SIZE + iNode; connElems[val_section][count] = (cgsize_t)connRecv[nn]; @@ -573,7 +573,7 @@ void CCGNSMeshReaderFVM::ReadCGNSSurfaceSection(int val_section) { connElems[val_section][iElem * SU2_CONN_SIZE + 0] = 0; connElems[val_section][iElem * SU2_CONN_SIZE + 1] = vtk_type; - for (iNode = 0; iNode < (unsigned long)npe; iNode++) { + for (iNode = 0; iNode < static_cast(npe); iNode++) { unsigned long nn = iElem * SU2_CONN_SIZE + SU2_CONN_SKIP + iNode; connElems[val_section][nn] = connElemTemp[counterCGNS] - 1; counterCGNS++; @@ -606,7 +606,7 @@ void CCGNSMeshReaderFVM::ReformatCGNSVolumeConnectivity() { for (unsigned long iElem = 0; iElem < nElems[s]; iElem++) { for (unsigned long iNode = 0; iNode < SU2_CONN_SIZE; iNode++) { unsigned long nn = iElem * SU2_CONN_SIZE + iNode; - localVolumeElementConnectivity[count] = (unsigned long)connElems[s][nn]; + localVolumeElementConnectivity[count] = static_cast(connElems[s][nn]); count++; } } @@ -640,7 +640,7 @@ void CCGNSMeshReaderFVM::ReformatCGNSSurfaceConnectivity() { for (unsigned long iElem = 0; iElem < nElems[s]; iElem++) { for (unsigned long iNode = 0; iNode < SU2_CONN_SIZE; iNode++) { unsigned long nn = iElem * SU2_CONN_SIZE + iNode; - surfaceElementConnectivity[markerCount][elementCount] = (unsigned long)connElems[s][nn]; + surfaceElementConnectivity[markerCount][elementCount] = static_cast(connElems[s][nn]); elementCount++; } } diff --git a/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp index 59d6bb74cfc..f1e8f6177a2 100644 --- a/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CRectangularMeshReaderFVM.cpp @@ -72,7 +72,7 @@ void CRectangularMeshReaderFVM::ComputeRectangularPointCoordinates() { /* Determine number of local points */ for (unsigned long globalIndex = 0; globalIndex < numberOfGlobalPoints; globalIndex++) { - if ((int)pointPartitioner.GetRankContainingIndex(globalIndex) == rank) { + if (static_cast(pointPartitioner.GetRankContainingIndex(globalIndex)) == rank) { numberOfLocalPoints++; } } @@ -84,7 +84,7 @@ void CRectangularMeshReaderFVM::ComputeRectangularPointCoordinates() { unsigned long globalIndex = 0; for (unsigned long jNode = 0; jNode < mNode; jNode++) { for (unsigned long iNode = 0; iNode < nNode; iNode++) { - if ((int)pointPartitioner.GetRankContainingIndex(globalIndex) == rank) { + if (static_cast(pointPartitioner.GetRankContainingIndex(globalIndex)) == rank) { /* Store the coordinates more clearly. */ const passivedouble x = SU2_TYPE::GetValue(Lx * ((su2double)iNode) / ((su2double)(nNode - 1)) + Ox); const passivedouble y = SU2_TYPE::GetValue(Ly * ((su2double)jNode) / ((su2double)(mNode - 1)) + Oy); @@ -121,7 +121,7 @@ void CRectangularMeshReaderFVM::ComputeRectangularVolumeConnectivity() { /* Check whether any of the points is in our linear partition. */ bool isOwned = false; for (unsigned short i = 0; i < N_POINTS_QUADRILATERAL; i++) { - if ((int)pointPartitioner.GetRankContainingIndex(connectivity[i]) == rank) { + if (static_cast(pointPartitioner.GetRankContainingIndex(connectivity[i])) == rank) { isOwned = true; } } diff --git a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp index 8403c6af425..6801123dd03 100644 --- a/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp +++ b/Common/src/geometry/meshreader/CSU2ASCIIMeshReaderFVM.cpp @@ -405,14 +405,14 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { elem_line >> connectivity[1]; elem_line >> connectivity[2]; InElem = false; - for (unsigned long i = 0; i < (unsigned long)N_POINTS_TRIANGLE; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_TRIANGLE); i++) { if (ActDisk_Bool[connectivity[i]]) { InElem = true; break; } } if (InElem) { - for (unsigned long i = 0; i < (unsigned long)N_POINTS_TRIANGLE; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_TRIANGLE); i++) { VolumePoint.push_back(connectivity[i]); } } @@ -423,14 +423,14 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { elem_line >> connectivity[2]; elem_line >> connectivity[3]; InElem = false; - for (unsigned long i = 0; i < (unsigned long)N_POINTS_QUADRILATERAL; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_QUADRILATERAL); i++) { if (ActDisk_Bool[connectivity[i]]) { InElem = true; break; } } if (InElem) { - for (unsigned long i = 0; i < (unsigned long)N_POINTS_QUADRILATERAL; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_QUADRILATERAL); i++) { VolumePoint.push_back(connectivity[i]); } } @@ -441,14 +441,14 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { elem_line >> connectivity[2]; elem_line >> connectivity[3]; InElem = false; - for (unsigned long i = 0; i < (unsigned long)N_POINTS_TETRAHEDRON; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_TETRAHEDRON); i++) { if (ActDisk_Bool[connectivity[i]]) { InElem = true; break; } } if (InElem) { - for (unsigned long i = 0; i < (unsigned long)N_POINTS_TETRAHEDRON; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_TETRAHEDRON); i++) { VolumePoint.push_back(connectivity[i]); } } @@ -463,14 +463,14 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { elem_line >> connectivity[6]; elem_line >> connectivity[7]; InElem = false; - for (unsigned long i = 0; i < (unsigned long)N_POINTS_HEXAHEDRON; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_HEXAHEDRON); i++) { if (ActDisk_Bool[connectivity[i]]) { InElem = true; break; } } if (InElem) { - for (unsigned long i = 0; i < (unsigned long)N_POINTS_HEXAHEDRON; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_HEXAHEDRON); i++) { VolumePoint.push_back(connectivity[i]); } } @@ -483,14 +483,14 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { elem_line >> connectivity[4]; elem_line >> connectivity[5]; InElem = false; - for (unsigned long i = 0; i < (unsigned long)N_POINTS_PRISM; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_PRISM); i++) { if (ActDisk_Bool[connectivity[i]]) { InElem = true; break; } } if (InElem) { - for (unsigned long i = 0; i < (unsigned long)N_POINTS_PRISM; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_PRISM); i++) { VolumePoint.push_back(connectivity[i]); } } @@ -502,14 +502,14 @@ void CSU2ASCIIMeshReaderFVM::SplitActuatorDiskSurface() { elem_line >> connectivity[3]; elem_line >> connectivity[4]; InElem = false; - for (unsigned long i = 0; i < (unsigned long)N_POINTS_PYRAMID; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_PYRAMID); i++) { if (ActDisk_Bool[connectivity[i]]) { InElem = true; break; } } if (InElem) { - for (unsigned long i = 0; i < (unsigned long)N_POINTS_PYRAMID; i++) { + for (unsigned long i = 0; i < static_cast(N_POINTS_PYRAMID); i++) { VolumePoint.push_back(connectivity[i]); } } diff --git a/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp b/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp index 6b374960f46..43fd3606a09 100644 --- a/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp +++ b/Common/src/geometry/primal_grid/CPrimalGridBoundFEM.cpp @@ -29,9 +29,9 @@ CPrimalGridBoundFEM::CPrimalGridBoundFEM(const unsigned long* dataElem) : CPrimalGrid(true, dataElem[2], 1) { /*--- Store the meta data for this element. ---*/ - VTK_Type = (unsigned short)dataElem[0]; - nPolyGrid = (unsigned short)dataElem[1]; - nDOFsGrid = (unsigned short)dataElem[2]; + VTK_Type = static_cast(dataElem[0]); + nPolyGrid = static_cast(dataElem[1]); + nDOFsGrid = static_cast(dataElem[2]); boundElemIDGlobal = dataElem[3]; GlobalIndex_DomainElement = dataElem[4]; diff --git a/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp b/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp index dbe2e4e3a03..738c443f3e8 100644 --- a/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp +++ b/Common/src/geometry/primal_grid/CPrimalGridFEM.cpp @@ -31,10 +31,10 @@ CPrimalGridFEM::CPrimalGridFEM(const unsigned long* dataElem, unsigned long& offsetSolDOFs) : CPrimalGrid(true, dataElem[3], nFacesOfElementType(dataElem[0])) { /*--- Store the meta data for this element. ---*/ - VTK_Type = (unsigned short)dataElem[0]; - nPolyGrid = (unsigned short)dataElem[1]; - nPolySol = (unsigned short)dataElem[2]; - nDOFsGrid = (unsigned short)dataElem[3]; + VTK_Type = static_cast(dataElem[0]); + nPolyGrid = static_cast(dataElem[1]); + nPolySol = static_cast(dataElem[2]); + nDOFsGrid = static_cast(dataElem[3]); nDOFsSol = CFEMStandardElementBase::GetNDOFsStatic(VTK_Type, nPolySol); elemIDGlobal = dataElem[4]; From bd5999fb9a60a10bbb6c70181fe93dcf4b2b48d1 Mon Sep 17 00:00:00 2001 From: vdweide Date: Thu, 6 Feb 2025 09:58:34 +0100 Subject: [PATCH 15/15] Result of running pre-commit --- Common/src/fem/fem_geometry_structure.cpp | 18 ++++++++++++------ Common/src/fem/geometry_structure_fem_part.cpp | 3 ++- Common/src/geometry/CPhysicalGeometry.cpp | 3 ++- 3 files changed, 16 insertions(+), 8 deletions(-) diff --git a/Common/src/fem/fem_geometry_structure.cpp b/Common/src/fem/fem_geometry_structure.cpp index 7a0b5177129..c6e52dbea81 100644 --- a/Common/src/fem/fem_geometry_structure.cpp +++ b/Common/src/fem/fem_geometry_structure.cpp @@ -566,8 +566,10 @@ CMeshFEM::CMeshFEM(CGeometry* geometry, CConfig* config) { the elements with constant and non-constant Jacobians are considered the same. */ if (JacConstant) { - const auto orderExactStraight = static_cast(ceil(nPolySol * config->GetQuadrature_Factor_Straight())); - const auto orderExactCurved = static_cast(ceil(nPolySol * config->GetQuadrature_Factor_Curved())); + const auto orderExactStraight = + static_cast(ceil(nPolySol * config->GetQuadrature_Factor_Straight())); + const auto orderExactCurved = + static_cast(ceil(nPolySol * config->GetQuadrature_Factor_Curved())); if (orderExactStraight == orderExactCurved) JacConstant = false; } @@ -2455,12 +2457,16 @@ void CMeshFEM_DG::CreateFaces(CConfig* config) { is set to false. Hence it is only needed to carry out this check for faces with a constant Jacobian. This is done to reduce the number of standard elements. */ if (thisFace.JacFaceIsConsideredConstant) { - auto orderExactStraight = static_cast(ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Straight())); - auto orderExactCurved = static_cast(ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Curved())); + auto orderExactStraight = + static_cast(ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Straight())); + auto orderExactCurved = + static_cast(ceil(thisFace.nPolyGrid0 * config->GetQuadrature_Factor_Curved())); if (orderExactStraight == orderExactCurved) { - orderExactStraight = static_cast(ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Straight())); - orderExactCurved = static_cast(ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Curved())); + orderExactStraight = + static_cast(ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Straight())); + orderExactCurved = + static_cast(ceil(thisFace.nPolySol0 * config->GetQuadrature_Factor_Curved())); if (orderExactStraight == orderExactCurved) thisFace.JacFaceIsConsideredConstant = false; } } diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index a0309bf2233..f4734eed85d 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -637,7 +637,8 @@ void CPhysicalGeometry::SetColorFEMGrid_Parallel(CConfig* config) { vector sendBufFace(9 * nFacesLocComm); vector counter(size); counter[0] = 0; - for (unsigned long i = 1; i < static_cast(size); ++i) counter[i] = counter[i - 1] + 9 * nFacesComm[i - 1]; + for (unsigned long i = 1; i < static_cast(size); ++i) + counter[i] = counter[i - 1] + 9 * nFacesComm[i - 1]; for (unsigned long i = 0; i < nFacesLocComm; ++i) { unsigned long rankFace = localFacesComm[i].elemID1; diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 1c53744b191..eab91fca43c 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -1990,7 +1990,8 @@ void CPhysicalGeometry::DistributeMarkerTags(CConfig* config, CGeometry* geometr /*--- Broadcast the string names of the variables. ---*/ - SU2_MPI::Bcast(mpi_str_buf, static_cast(nMarker_Global) * MAX_STRING_SIZE, MPI_CHAR, MASTER_NODE, SU2_MPI::GetComm()); + SU2_MPI::Bcast(mpi_str_buf, static_cast(nMarker_Global) * MAX_STRING_SIZE, MPI_CHAR, MASTER_NODE, + SU2_MPI::GetComm()); /*--- Now parse the string names and load into our marker tag vector. We also need to set the values of all markers into the config. ---*/