diff --git a/Common/include/CMultiGridQueue.hpp b/Common/include/CMultiGridQueue.hpp index e4312375aade..9d66c4771a41 100644 --- a/Common/include/CMultiGridQueue.hpp +++ b/Common/include/CMultiGridQueue.hpp @@ -31,7 +31,7 @@ #include #include "mpi_structure.hpp" -#include "geometry_structure.hpp" +#include "geometry/CGeometry.hpp" using namespace std; diff --git a/Common/include/fem_geometry_structure.hpp b/Common/include/fem_geometry_structure.hpp index 4fae465d5b1f..221d04a66b7e 100644 --- a/Common/include/fem_geometry_structure.hpp +++ b/Common/include/fem_geometry_structure.hpp @@ -28,7 +28,11 @@ #pragma once -#include "geometry_structure.hpp" +#include "geometry/CGeometry.hpp" +#include "fem_standard_element.hpp" +#ifdef HAVE_CGNS +#include "fem_cgns_elements.hpp" +#endif #include "wall_model.hpp" #include "blas_structure.hpp" @@ -1042,9 +1046,9 @@ class CMeshFEM_DG: public CMeshFEM { /*! * \brief Retrieve total number of nodes in a simulation across all processors (excluding halos). - * \returns Total number of nodes in a simulation across all processors (excluding halos). + * \return Total number of nodes in a simulation across all processors (excluding halos). */ - unsigned long GetGlobal_nPointDomain(); + unsigned long GetGlobal_nPointDomain() const override; /*! * \brief Set the local index that correspond with the global numbering index. @@ -1054,9 +1058,9 @@ class CMeshFEM_DG: public CMeshFEM { /*! * \brief Get the local index that correspond with the global numbering index. * \param[in] val_ipoint - Global point. - * \returns Local index that correspond with the global index, -1 if not found on the current rank. + * \return Local index that correspond with the global index, -1 if not found on the current rank. */ - long GetGlobal_to_Local_Point(unsigned long val_ipoint); + long GetGlobal_to_Local_Point(unsigned long val_ipoint) const override; /*! * \brief Function, which carries out the preprocessing tasks diff --git a/Common/include/fem_geometry_structure.inl b/Common/include/fem_geometry_structure.inl index 825669101c63..b00d06e66bd9 100644 --- a/Common/include/fem_geometry_structure.inl +++ b/Common/include/fem_geometry_structure.inl @@ -146,7 +146,7 @@ inline CMeshFEM_DG::~CMeshFEM_DG(void) { } inline void CMeshFEM_DG::SetGlobal_nPointDomain(unsigned long val_global_npoint) { Global_nPointDomain = val_global_npoint; } -inline unsigned long CMeshFEM_DG::GetGlobal_nPointDomain(void) { return Global_nPointDomain; } +inline unsigned long CMeshFEM_DG::GetGlobal_nPointDomain(void) const { return Global_nPointDomain; } inline void CMeshFEM_DG::SetGlobal_to_Local_Point(void) { Global_to_Local_Point.clear(); @@ -158,13 +158,11 @@ inline void CMeshFEM_DG::SetGlobal_to_Local_Point(void) { } } -inline long CMeshFEM_DG::GetGlobal_to_Local_Point(unsigned long val_ipoint) { - map::const_iterator MI = Global_to_Local_Point.find(val_ipoint); - if (MI != Global_to_Local_Point.end()) { - return Global_to_Local_Point[val_ipoint]; - } else { - return -1; - } +inline long CMeshFEM_DG::GetGlobal_to_Local_Point(unsigned long val_ipoint) const { + auto it = Global_to_Local_Point.find(val_ipoint); + if (it != Global_to_Local_Point.cend()) + return it->second; + return -1; } inline su2double* CMeshFEM_DG::GetTimeCoefADER_DG(void) {return timeCoefADER_DG.data();} diff --git a/Common/include/geometry/CDummyGeometry.hpp b/Common/include/geometry/CDummyGeometry.hpp new file mode 100644 index 000000000000..88576d2d5db3 --- /dev/null +++ b/Common/include/geometry/CDummyGeometry.hpp @@ -0,0 +1,54 @@ +/*! + * \file CDummyGeometry.hpp + * \brief Headers of the dummy geometry class used in "dry run" mode. + * \author T. Albring + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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 "CGeometry.hpp" + +/*! + * \class CDummyGeometry + * \brief Class for defining a geometry that does not contain any points/elements. + * Can be used for initializing other classes that depend on the geometry without + * going through the time-consuming mesh initialization and paritioning. + * \author T. Albring + */ +class CDummyGeometry final : public CGeometry{ + +public: + /*! + * \brief Constructor of the class + * \param[in] config - Definition of the particular problem. + */ + CDummyGeometry(CConfig *config); + + /*! + * \brief Destructor of the class. + */ + ~CDummyGeometry(); + +}; + diff --git a/Common/include/geometry/CGeometry.hpp b/Common/include/geometry/CGeometry.hpp new file mode 100644 index 000000000000..0131d2e6fbac --- /dev/null +++ b/Common/include/geometry/CGeometry.hpp @@ -0,0 +1,1545 @@ +/*! + * \file CGeometry.hpp + * \brief Headers of the main subroutines for creating the geometrical structure. + * The subroutines and functions are in the CGeometry.cpp file. + * \author F. Palacios, T. Economon + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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 "../mpi_structure.hpp" + +#ifdef HAVE_METIS +#include "metis.h" +#endif +#ifdef HAVE_PARMETIS +extern "C" { +#include "parmetis.h" +} +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include "../primal_grid_structure.hpp" +#include "../dual_grid_structure.hpp" +#include "../config_structure.hpp" +#include "../geometry_structure_fem_part.hpp" + +using namespace std; + +/*! + * \class CGeometry + * \brief Parent class for defining the geometry of the problem (complete geometry, + * multigrid agglomerated geometry, only boundary geometry, etc..) + * \author F. Palacios + */ +class CGeometry { +protected: + int rank; /*!< \brief MPI Rank. */ + int size; /*!< \brief MPI Size. */ + + unsigned long nPoint, /*!< \brief Number of points of the mesh. */ + nPointDomain, /*!< \brief Number of real points of the mesh. */ + nPointGhost, /*!< \brief Number of ghost points of the mesh. */ + nPointNode, /*!< \brief Size of the node array allocated to hold CPoint objects. */ + Global_nPoint, /*!< \brief Total number of nodes in a simulation across all processors (including halos). */ + Global_nPointDomain, /*!< \brief Total number of nodes in a simulation across all processors (excluding halos). */ + nElem, /*!< \brief Number of elements of the mesh. */ + Global_nElem, /*!< \brief Total number of elements in a simulation across all processors (all types). */ + Global_nElemDomain, /*!< \brief Total number of elements in a simulation across all processors (excluding halos). */ + nEdge, /*!< \brief Number of edges of the mesh. */ + nFace, /*!< \brief Number of faces of the mesh. */ + nelem_edge, /*!< \brief Number of edges in the mesh. */ + Global_nelem_edge, /*!< \brief Total number of edges in the mesh across all processors. */ + nelem_triangle, /*!< \brief Number of triangles in the mesh. */ + Global_nelem_triangle, /*!< \brief Total number of triangles in the mesh across all processors. */ + nelem_quad, /*!< \brief Number of quadrangles in the mesh. */ + Global_nelem_quad, /*!< \brief Total number of quadrangles in the mesh across all processors. */ + nelem_tetra, /*!< \brief Number of tetrahedra in the mesh. */ + Global_nelem_tetra, /*!< \brief Total number of tetrahedra in the mesh across all processors. */ + nelem_hexa, /*!< \brief Number of hexahedra in the mesh. */ + Global_nelem_hexa, /*!< \brief Total number of hexahedra in the mesh across all processors. */ + nelem_prism, /*!< \brief Number of prisms in the mesh. */ + Global_nelem_prism, /*!< \brief Total number of prisms in the mesh across all processors. */ + nelem_pyramid, /*!< \brief Number of pyramids in the mesh. */ + Global_nelem_pyramid, /*!< \brief Total number of pyramids in the mesh across all processors. */ + nelem_edge_bound, /*!< \brief Number of edges on the mesh boundaries. */ + Global_nelem_edge_bound, /*!< \brief Total number of edges on the mesh boundaries across all processors. */ + nelem_triangle_bound, /*!< \brief Number of triangles on the mesh boundaries. */ + Global_nelem_triangle_bound, /*!< \brief Total number of triangles on the mesh boundaries across all processors. */ + nelem_quad_bound, /*!< \brief Number of quads on the mesh boundaries. */ + Global_nelem_quad_bound; /*!< \brief Total number of quads on the mesh boundaries across all processors. */ + + unsigned short nDim, /*!< \brief Number of dimension of the problem. */ + nZone, /*!< \brief Number of zones in the problem. */ + nMarker; /*!< \brief Number of different markers of the mesh. */ + + unsigned short MGLevel; /*!< \brief The mesh level index for the current geometry container. */ + unsigned long Max_GlobalPoint; /*!< \brief Greater global point in the domain local structure. */ + + /* --- Custom boundary variables --- */ + su2double **CustomBoundaryTemperature; + su2double **CustomBoundaryHeatFlux; + +public: + unsigned long *nElem_Bound; /*!< \brief Number of elements of the boundary. */ + string *Tag_to_Marker; /*!< \brief If you know the index of the boundary (depend of the grid definition), + it gives you the maker (where the boundary is stored from 0 to boundaries). */ + CPrimalGrid** elem; /*!< \brief Element vector (primal grid information). */ + CPrimalGrid** face; /*!< \brief Face vector (primal grid information). */ + CPrimalGrid*** bound; /*!< \brief Boundary vector (primal grid information). */ + CPoint** node; /*!< \brief Node vector (dual grid information). */ + CEdge** edge; /*!< \brief Edge vector (dual grid information). */ + CVertex*** vertex; /*!< \brief Boundary Vertex vector (dual grid information). */ + CTurboVertex**** turbovertex; /*!< \brief Boundary Vertex vector ordered for turbomachinery calculation(dual grid information). */ + unsigned long *nVertex; /*!< \brief Number of vertex for each marker. */ + vector bound_is_straight; /*!< \brief Bool if boundary-marker is straight(2D)/plane(3D) for each local marker. */ + unsigned short *nSpanWiseSections; /*!< \brief Number of Span wise section for each turbo marker, indexed by inflow/outflow */ + unsigned short *nSpanSectionsByMarker; /*!< \brief Number of Span wise section for each turbo marker, indexed by marker. Needed for deallocation.*/ + unsigned short nTurboPerf; /*!< \brief Number of Span wise section for each turbo marker. */ + su2double **SpanWiseValue; /*!< \brief Span wise values for each turbo marker. */ + long **nVertexSpan; /*!< \brief number of vertexes for span wise section for each marker. */ + unsigned long **nTotVertexSpan; /*!< \brief number of vertexes at each span wise section for each marker. */ + unsigned long nVertexSpanMax[3]; /*!< \brief max number of vertexes for each span section for each marker flag. */ + su2double ***AverageTurboNormal; /*!< \brief Average boundary normal at each span wise section for each marker in the turbomachinery frame of reference.*/ + su2double ***AverageNormal; /*!< \brief Average boundary normal at each span wise section for each marker.*/ + su2double ***AverageGridVel; /*!< \brief Average boundary grid velocity at each span wise section for each marker.*/ + su2double **AverageTangGridVel; /*!< \brief Average tangential rotational speed at each span wise section for each marker.*/ + su2double **SpanArea; /*!< \brief Area at each span wise section for each marker.*/ + su2double **MaxAngularCoord; /*!< \brief Max angular pitch at each span wise section for each marker.*/ + su2double **MinAngularCoord; /*!< \brief Max angular pitch at each span wise section for each marker.*/ + su2double **MinRelAngularCoord; /*!< \brief Min relative angular coord at each span wise section for each marker.*/ + su2double **TurboRadius; /*!< \brief Radius at each span wise section for each marker.*/ + su2double **TangGridVelIn, + **TangGridVelOut; /*!< \brief Average tangential rotational speed at each span wise section for each turbomachinery marker.*/ + su2double **SpanAreaIn, + **SpanAreaOut; /*!< \brief Area at each span wise section for each turbomachinery marker.*/ + su2double **TurboRadiusIn, + **TurboRadiusOut; /*!< \brief Radius at each span wise section for each turbomachinery marker*/ + + unsigned short nCommLevel; /*!< \brief Number of non-blocking communication levels. */ + + short *Marker_All_SendRecv; /*!< \brief MPI Marker. */ + + /*--- Create vectors and distribute the values among the different planes queues ---*/ + vector > Xcoord_plane; /*!< \brief Vector containing x coordinates of new points appearing on a single plane */ + vector > Ycoord_plane; /*!< \brief Vector containing y coordinates of new points appearing on a single plane */ + vector > Zcoord_plane; /*!< \brief Vector containing z coordinates of new points appearing on a single plane */ + vector > FaceArea_plane; /*!< \brief Vector containing area/volume associated with new points appearing on a single plane */ + vector > Plane_points; /*!< \brief Vector containing points appearing on a single plane */ + + vector XCoordList; /*!< \brief Vector containing points appearing on a single plane */ + CPrimalGrid*** newBound; /*!< \brief Boundary vector for new periodic elements (primal grid information). */ + unsigned long *nNewElem_Bound; /*!< \brief Number of new periodic elements of the boundary. */ + + /*--- Partitioning-specific variables ---*/ + + map Global_to_Local_Elem; /*!< \brief Mapping of global to local index for elements. */ + unsigned long *beg_node; /*!< \brief Array containing the first node on each rank due to a linear partitioning by global index. */ + unsigned long *end_node; /*!< \brief Array containing the last node on each rank due to a linear partitioning by global index. */ + unsigned long *nPointLinear; /*!< \brief Array containing the total number of nodes on each rank due to a linear partioning by global index. */ + unsigned long *nPointCumulative; /*!< \brief Cumulative storage array containing the total number of points on all prior ranks in the linear partitioning. */ + +#ifdef HAVE_MPI +#ifdef HAVE_PARMETIS + vector< vector > adj_nodes; /*!< \brief Vector of vectors holding each node's adjacency during preparation for ParMETIS. */ + idx_t *adjacency; /*!< \brief Local adjacency array to be input into ParMETIS for partitioning (idx_t is a ParMETIS type defined in their headers). */ + idx_t *xadj; /*!< \brief Index array that points to the start of each node's adjacency in CSR format (needed to interpret the adjacency array). */ +#endif +#endif + + /*--- Data structures for point-to-point MPI communications. ---*/ + + int countPerPoint; /*!< \brief Maximum number of pieces of data sent per vertex in point-to-point comms. */ + int nP2PSend; /*!< \brief Number of sends during point-to-point comms. */ + int nP2PRecv; /*!< \brief Number of receives during point-to-point comms. */ + int *nPoint_P2PSend; /*!< \brief Data structure holding number of vertices for each send in point-to-point comms. */ + int *nPoint_P2PRecv; /*!< \brief Data structure holding number of vertices for each recv in point-to-point comms. */ + int *Neighbors_P2PSend; /*!< \brief Data structure holding the ranks of the neighbors for point-to-point send comms. */ + int *Neighbors_P2PRecv; /*!< \brief Data structure holding the ranks of the neighbors for point-to-point recv comms. */ + map P2PSend2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for point-to-point send comms. */ + map P2PRecv2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for point-to-point recv comms. */ + unsigned long *Local_Point_P2PSend; /*!< \brief Data structure holding the local index of all vertices to be sent in point-to-point comms. */ + unsigned long *Local_Point_P2PRecv; /*!< \brief Data structure holding the local index of all vertices to be received in point-to-point comms. */ + su2double *bufD_P2PRecv; /*!< \brief Data structure for su2double point-to-point receive. */ + su2double *bufD_P2PSend; /*!< \brief Data structure for su2double point-to-point send. */ + unsigned short *bufS_P2PRecv; /*!< \brief Data structure for unsigned long point-to-point receive. */ + unsigned short *bufS_P2PSend; /*!< \brief Data structure for unsigned long point-to-point send. */ + SU2_MPI::Request *req_P2PSend; /*!< \brief Data structure for point-to-point send requests. */ + SU2_MPI::Request *req_P2PRecv; /*!< \brief Data structure for point-to-point recv requests. */ + + /*--- Data structures for periodic communications. ---*/ + + int countPerPeriodicPoint; /*!< \brief Maximum number of pieces of data sent per vertex in periodic comms. */ + int nPeriodicSend; /*!< \brief Number of sends during periodic comms. */ + int nPeriodicRecv; /*!< \brief Number of receives during periodic comms. */ + int *nPoint_PeriodicSend; /*!< \brief Data structure holding number of vertices for each send in periodic comms. */ + int *nPoint_PeriodicRecv; /*!< \brief Data structure holding number of vertices for each recv in periodic comms. */ + int *Neighbors_PeriodicSend; /*!< \brief Data structure holding the ranks of the neighbors for periodic send comms. */ + int *Neighbors_PeriodicRecv; /*!< \brief Data structure holding the ranks of the neighbors for periodic recv comms. */ + map PeriodicSend2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for periodic send comms. */ + map PeriodicRecv2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for periodic recv comms. */ + unsigned long *Local_Point_PeriodicSend; /*!< \brief Data structure holding the local index of all vertices to be sent in periodic comms. */ + unsigned long *Local_Point_PeriodicRecv; /*!< \brief Data structure holding the local index of all vertices to be received in periodic comms. */ + unsigned long *Local_Marker_PeriodicSend; /*!< \brief Data structure holding the local index of the periodic marker for a particular vertex to be sent in periodic comms. */ + unsigned long *Local_Marker_PeriodicRecv; /*!< \brief Data structure holding the local index of the periodic marker for a particular vertex to be received in periodic comms. */ + su2double *bufD_PeriodicRecv; /*!< \brief Data structure for su2double periodic receive. */ + su2double *bufD_PeriodicSend; /*!< \brief Data structure for su2double periodic send. */ + unsigned short *bufS_PeriodicRecv; /*!< \brief Data structure for unsigned long periodic receive. */ + unsigned short *bufS_PeriodicSend; /*!< \brief Data structure for unsigned long periodic send. */ + SU2_MPI::Request *req_PeriodicSend; /*!< \brief Data structure for periodic send requests. */ + SU2_MPI::Request *req_PeriodicRecv; /*!< \brief Data structure for periodic recv requests. */ + + vector Orthogonality; /*!< \brief Measure of dual CV orthogonality angle (0 to 90 deg., 90 being best). */ + vector Aspect_Ratio; /*!< \brief Measure of dual CV aspect ratio (max face area / min face area). */ + vector Volume_Ratio; /*!< \brief Measure of dual CV volume ratio (max sub-element volume / min sub-element volume). */ + + /*! + * \brief Constructor of the class. + */ + CGeometry(void); + + /*! + * \brief Constructor of the class. + */ + CGeometry(CConfig *config, unsigned short nDim); + + /*! + * \brief Destructor of the class. + */ + virtual ~CGeometry(void); + + /*! + * \brief Routine to launch non-blocking recvs only for all periodic communications. + * \brief Routine to set up persistent data structures for point-to-point MPI communications. + * \note This routine is called by any class that has loaded data into the generic communication buffers. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void PreprocessP2PComms(CGeometry *geometry, CConfig *config); + + /*! + * \brief Routine to allocate buffers for point-to-point MPI communications. Also called to dynamically reallocate if not enough memory is found for comms during runtime. + * \param[in] val_countPerPoint - Maximum count of the data type per vertex in point-to-point comms, e.g., nPrimvarGrad*nDim. + */ + void AllocateP2PComms(unsigned short val_countPerPoint); + + /*! + * \brief Routine to launch non-blocking recvs only for all point-to-point communication with neighboring partitions. + * \note This routine is called by any class that has loaded data into the generic communication buffers. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] commType - Enumerated type for the quantity to be communicated. + * \param[in] val_reverse - Boolean controlling forward or reverse communication between neighbors. + */ + void PostP2PRecvs(CGeometry *geometry, CConfig *config, unsigned short commType, bool val_reverse); + + /*! + * \brief Routine to launch a single non-blocking send once the buffer is loaded for a point-to-point commucation. + * \note This routine is called by any class that has loaded data into the generic communication buffers. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] commType - Enumerated type for the quantity to be communicated. + * \param[in] val_iMessage - Index of the message in the order they are stored. + * \param[in] val_reverse - Boolean controlling forward or reverse communication between neighbors. + */ + void PostP2PSends(CGeometry *geometry, CConfig *config, unsigned short commType, int val_iMessage, bool val_reverse); + + /*! + * \brief Routine to set up persistent data structures for periodic communications. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void PreprocessPeriodicComms(CGeometry *geometry, CConfig *config); + + /*! + * \brief Routine to allocate buffers for periodic communications. Also called to dynamically reallocate if not enough memory is found for comms during runtime. + * \param[in] val_countPerPeriodicPoint - Maximum count of the data type per vertex in periodic comms, e.g., nPrimvarGrad*nDim. + */ + void AllocatePeriodicComms(unsigned short val_countPerPeriodicPoint); + + /*! + * \brief Routine to launch non-blocking recvs only for all periodic communication with neighboring partitions. + * \note This routine is called by any class that has loaded data into the generic communication buffers. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] commType - Enumerated type for the quantity to be communicated. + */ + void PostPeriodicRecvs(CGeometry *geometry, CConfig *config, unsigned short commType); + + /*! + * \brief Routine to launch a single non-blocking send once the buffer is loaded for a periodic commucation. + * \note This routine is called by any class that has loaded data into the generic communication buffers. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] commType - Enumerated type for the quantity to be communicated. + * \param[in] val_iMessage - Index of the message in the order they are stored. + */ + void PostPeriodicSends(CGeometry *geometry, CConfig *config, unsigned short commType, int val_iMessage); + + /*! + * \brief Routine to load a geometric quantity into the data structures for MPI point-to-point communication and to + * launch non-blocking sends and recvs for all point-to-point communication with neighboring partitions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] commType - Enumerated type for the quantity to be communicated. + */ + void InitiateComms(CGeometry *geometry, CConfig *config, unsigned short commType); + + /*! + * \brief Routine to complete the set of non-blocking communications launched by InitiateComms() and unpacking of the data into the geometry class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] commType - Enumerated type for the quantity to be unpacked. + */ + void CompleteComms(CGeometry *geometry, CConfig *config, unsigned short commType); + + /*! + * \brief Get number of coordinates. + * \return Number of coordinates. + */ + inline unsigned short GetnDim(void) const {return nDim;} + + /*! + * \brief Get number of zones. + * \return Number of zones. + */ + inline unsigned short GetnZone(void) const {return nZone;} + + /*! + * \brief Get number of points. + * \return Number of points. + */ + inline unsigned long GetnPoint(void) const {return nPoint;} + + /*! + * \brief Get number of real points (that belong to the domain). + * \return Number of real points. + */ + inline unsigned long GetnPointDomain(void) const {return nPointDomain;} + + /*! + * \brief Get number of elements. + * \return Number of elements. + */ + unsigned long GetnLine(void); + + /*! + * \brief Get number of elements. + * \return Number of elements. + */ + inline unsigned long GetnElem(void) const {return nElem;} + + /*! + * \brief Get number of edges. + * \return Number of edges. + */ + inline unsigned long GetnEdge(void) const {return nEdge;} + + /*! + * \brief Get number of markers. + * \return Number of markers. + */ + inline unsigned short GetnMarker(void) const {return nMarker;} + + /*! + * \brief Get number of vertices. + * \param[in] val_marker - Marker of the boundary. + * \return Number of vertices. + */ + inline const su2double* GetSpanWiseValue(unsigned short val_marker) const { return SpanWiseValue[val_marker-1]; } + + /*! + * \brief Get number of vertices. + * \param[in] val_marker - Marker of the boundary. + * \return Number of vertices. + */ + inline unsigned long GetnVertex(unsigned short val_marker) const { return nVertex[val_marker]; } + + /*! + * \brief Get number of span wise section. + * \param[in] marker_flag - flag of the turbomachinery boundary. + * \return Number of span wise section. + */ + inline unsigned short GetnSpanWiseSections(unsigned short marker_flag) const { return nSpanWiseSections[marker_flag -1]; } + + /*! + * \brief Get number of vertices. + * \param[in] val_marker - Marker of the boundary. + * \return Number of vertices. + */ + inline unsigned long GetnVertexSpan(unsigned short val_marker, unsigned short val_span) const { return nVertexSpan[val_marker][val_span]; } + + /*! + * \brief Get number of frequencies per span for NRBC. + * \param[in] val_marker - Marker of the boundary. + * \return Number of frequencies for NRBC. + */ + inline unsigned long GetnFreqSpan(unsigned short val_marker, unsigned short val_span) const { return (nTotVertexSpan[val_marker][val_span]/2 -1); } + + /*! + * \brief Get number of vertices. + * \param[in] val_marker - Marker of the boundary. + * \return Number of vertices. + */ + inline unsigned long GetnVertexSpanMax(unsigned short marker_flag) const { return nVertexSpanMax[marker_flag]; } + + /*! + * \brief Get number of max frequencies for initializing the Fourier Coefficient for NR BC. + * \param[in] marker_flag - Marker of the boundary. + * \return Number of frequencies. + */ + inline unsigned long GetnFreqSpanMax(unsigned short marker_flag) const { return (nVertexSpanMax[marker_flag]/2 -1); } + + /*! + * \brief Get number of vertices. + * \param[in] val_marker - Marker of the boundary. + * \return Number of vertices. + */ + inline void SetnVertexSpanMax(unsigned short marker_flag, unsigned long nVertMax) {nVertexSpanMax[marker_flag] = nVertMax;} + + /*! + * \brief Get the edge index from using the nodes of the edge. + * \param[in] first_point - First point of the edge. + * \param[in] second_point - Second point of the edge. + * \return Index of the edge. + */ + long FindEdge(unsigned long first_point, unsigned long second_point); + + /*! + * \brief Get the edge index from using the nodes of the edge. + * \param[in] first_point - First point of the edge. + * \param[in] second_point - Second point of the edge. + * \return Index of the edge. + */ + bool CheckEdge(unsigned long first_point, unsigned long second_point); + + /*! + * \brief Get the distance between a plane (defined by three point) and a point. + * \param[in] Coord - Coordinates of the point. + * \param[in] iCoord - Coordinates of the first point that defines the plane. + * \param[in] jCoord - Coordinates of the second point that defines the plane. + * \param[in] kCoord - Coordinates of the third point that defines the plane. + * \return Signed distance. + */ + su2double Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord); + + /*! + * \brief Create a file for testing the geometry. + */ + void TestGeometry(void); + + /*! + * \brief A virtual member. + * \param[in] val_nmarker - Number of markers. + */ + inline void SetnMarker(unsigned short val_nmarker) { nMarker = val_nmarker; } + + /*! + * \brief Set the number of dimensions of the problem. + * \param[in] val_nDim - Number of dimensions. + */ + inline void SetnDim(unsigned short val_nDim) { nDim = val_nDim; } + + /*! + * \brief Get the index of a marker. + * \param[in] val_marker - Marker of the boundary. + * \return Index of the marker in the grid defintion. + */ + inline string GetMarker_Tag(unsigned short val_marker) const { return Tag_to_Marker[val_marker]; } + + /*! + * \brief Set index of a marker. + * \param[in] val_marker - Marker of the boundary. + * \param[in] val_index - Index of the marker. + */ + inline void SetMarker_Tag(unsigned short val_marker, string val_index) { Tag_to_Marker[val_marker] = std::move(val_index); } + + /*! + * \brief Set the number of boundary elements. + * \param[in] val_marker - Marker of the boundary. + * \param[in] val_nelem_bound - Number of boundary elements. + */ + inline void SetnElem_Bound(unsigned short val_marker, unsigned long val_nelem_bound) { + nElem_Bound[val_marker]= val_nelem_bound; + } + + /*! + * \brief Set the number of grid points. + * \param[in] val_npoint - Number of grid points. + */ + inline void SetnPoint(unsigned long val_npoint) { nPoint = val_npoint; } + + /*! + * \brief Set the number of grid points in the domain. + * \param[in] val_npoint - Number of grid points in the domain. + */ + inline void SetnPointDomain(unsigned long val_npoint) { nPointDomain = val_npoint; } + + /*! + * \brief Set the number of grid elements. + * \param[in] val_nelem - Number of grid elements. + */ + inline void SetnElem(unsigned long val_nelem) { nElem = val_nelem; } + + /*! + * \brief Get the number of boundary elements. + * \param[in] val_marker - Marker of the boundary. + */ + inline unsigned long GetnElem_Bound(unsigned short val_marker) const { return nElem_Bound[val_marker]; } + + /*! + * \brief Get the number of elements in vtk fortmat. + */ + inline unsigned long GetMax_GlobalPoint(void) const { return Max_GlobalPoint; } + + /*! + * \brief Finds face of element. + * \param[in] first_elem - Identification of the first element. + * \param[in] second_elem - Identification of the second element. + * \param[in] face_first_elem - Index of the common face for the first element. + * \param[in] face_second_elem - Index of the common face for the second element. + */ + inline virtual bool FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, + unsigned short &face_second_elem) {return false;} + + /*! + * \brief Computes the wall distance. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void ComputeWall_Distance(CConfig *config) {} + + /*! + * \brief Sets area to be positive in Z direction. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetPositive_ZArea(CConfig *config) {} + + /*! + * \brief Setas connectivity between points. + */ + inline virtual void SetPoint_Connectivity(void) {} + + /*! + * \brief Orders the RCM. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetRCM_Ordering(CConfig *config) {} + + /*! + * \brief Connects elements . + */ + inline virtual void SetElement_Connectivity(void) {} + + /*! + * \brief Sets the edges of an elemment. + */ + void SetEdges(void); + + /*! + * \brief Sets the faces of an element.. + */ + void SetFaces(void); + + /*! + * \brief Sets the boundary volume. + */ + inline virtual void SetBoundVolume(void) {} + + /*! + * \brief Sets the vertices. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetVertex(CConfig *config) {} + + /*! + * \brief Computes the N span. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Zone of the problem + * \param[in] marker_flag - Marker being used + * \param[in] allocate + */ + inline virtual void ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) {} + + /*! + * \brief Set vertices for turbomachinery problems. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Zone of the problem + * \param[in] marker_flag - Marker being used + * \param[in] allocate + */ + inline virtual void SetTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Zone of the problem + * \param[in] marker_flag - Marker being used + */ + inline virtual void UpdateTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Zone of the problem + * \param[in] marker_flag - Marker being used + * \param[in] allocate + */ + inline virtual void SetAvgTurboValue(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] allocate + */ + inline virtual void GatherInOutAverageValues(CConfig *config, bool allocate) {} + + /*! + * \brief Sets CG coordinates. + */ + inline virtual void SetCoord_CG(void) {} + + /*! + * \brief Set max length. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetMaxLength(CConfig* config) {} + + /*! + * \brief Sets control volume. + * \param[in] config - Definition of the particular problem. + * \param[in] action - Allocate or not the new elements. + */ + inline virtual void SetControlVolume(CConfig *config, unsigned short action) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] action - Allocate or not the new elements. + */ + inline virtual void VisualizeControlVolume(CConfig *config, unsigned short action) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void MatchNearField(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void MatchActuator_Disk(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void MatchPeriodic(CConfig *config, unsigned short val_periodic) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] action - Allocate or not the new elements. + */ + inline virtual void SetBoundControlVolume(CConfig *config, unsigned short action) {} + + /*! + * \brief A virtual member. + * \param[in] config_filename - Name of the file where the tecplot information is going to be stored. + */ + inline virtual void SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file) {} + + /*! + * \brief A virtual member. + * \param[in] mesh_filename - Name of the file where the tecplot information is going to be stored. + * \param[in] new_file - Boolean to decide if aopen a new file or add to a old one + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void Check_IntElem_Orientation(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void Check_BoundElem_Orientation(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetColorGrid(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetColorGrid_Parallel(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetColorFEMGrid_Parallel(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void DivideConnectivity(CConfig *config, unsigned short Elem_Type) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_domain - Number of domains for parallelization purposes. + */ + inline virtual void SetSendReceive(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_domain - Number of domains for parallelization purposes. + */ + inline virtual void SetBoundaries(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + */ + inline virtual void SetCoord(CGeometry *geometry) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_marker - Index of the boundary marker. + */ + inline virtual void SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_marker - Index of the boundary marker. + */ + inline virtual void SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker) {} + + /*! + * \brief A virtual member. + * \param[in] val_nSmooth - Number of smoothing iterations. + * \param[in] val_smooth_coeff - Relaxation factor. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetCoord_Smoothing(unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + */ + inline virtual void SetPoint_Connectivity(CGeometry *geometry) {} + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetVertex(CGeometry *geometry, CConfig *config) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] action - Allocate or not the new elements. + */ + inline virtual void SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] action - Allocate or not the new elements. + */ + inline virtual void SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] val_mesh_out_filename - Name of the output file. + */ + inline virtual void SetMeshFile(CConfig *config, string val_mesh_out_filename) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + * \param[in] val_mesh_out_filename - Name of the output file. + */ + inline virtual void SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetBoundSensitivity(CConfig *config) {} + + /*! + * \brief Set the data containers for customized boundary conditions. + * \param[in] config - Definition of the particular problem. + */ + void SetCustomBoundary(CConfig *config); + + /*! + * \brief Set cartesian grid velocity based on rotational speed and axis. + * \param[in] config - Definition of the particular problem. + * \param[in] print - Display information on screen. + */ + void SetRotationalVelocity(CConfig *config, bool print = false); + + /*! + * \brief Set the rotational velocity of the points on the shroud markers to 0. + * \param[in] config - Definition of the particular problem. + */ + void SetShroudVelocity(CConfig *config); + + /*! + * \brief Set the translational velocity at each node. + * \param[in] config - Definition of the particular problem. + * \param[in] print - Display information on screen. + */ + void SetTranslationalVelocity(CConfig *config, bool print = false); + + /*! + * \brief Set the grid velocity via finite differencing at each node. + * \param[in] config - Definition of the particular problem. + * \param[in] iter - Current physical time step. + */ + void SetGridVelocity(CConfig *config, unsigned long iter); + + /*! + * \brief A virtual member. + * \param[in] geometry - Geometry of the fine mesh. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) {} + + /*! + * \brief Check if a boundary is straight(2D) / plane(3D) for EULER_WALL and SYMMETRY_PLANE + * only and store the information in bound_is_straight. For all other boundary types + * this will return false and could therfore be wrong. Used ultimately for BC_Slip_Wall. + * \param[in] config - Definition of the particular problem. + * \param[in] print_on_screen - Boolean whether to print result on screen. + */ + void ComputeSurf_Straightness(CConfig *config, bool print_on_screen); + + /*! + * \brief Find and store all vertices on a sharp corner in the geometry. + * \param[in] config - Definition of the particular problem. + */ + void ComputeSurf_Curvature(CConfig *config); + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + void ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, + su2double MinXCoord, su2double MaxXCoord, + su2double MinYCoord, su2double MaxYCoord, + su2double MinZCoord, su2double MaxZCoord, + su2double *FlowVariable, + vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, + vector &Zcoord_Airfoil, vector &Variable_Airfoil, + bool original_surface, CConfig *config); + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, + vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, + vector &Zcoord_Airfoil, su2double &ZLoc) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual void Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector + &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {} + + /*! + * \brief A virtual member. + */ + virtual void Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector + &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) {} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, + su2double *LeadingEdge_i, su2double *TrailingEdge_i) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual su2double Compute_Curvature(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, + su2double *LeadingEdge_i, su2double *TrailingEdge_i, + su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1) {return 0.0;} + + /*! + * \brief A virtual member. + */ + virtual void Compute_Wing(CConfig *config, bool original_surface, + su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, su2double &Wing_MinChord, su2double &Wing_MaxChord, + su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius, + su2double &Wing_MinToC, su2double &Wing_MaxToC, su2double &Wing_ObjFun_MinToC, su2double &Wing_MaxTwist, su2double &Wing_MaxCurvature, + su2double &Wing_MaxDihedral) {} + + /*! + * \brief A virtual member. + */ + virtual void Compute_Fuselage(CConfig *config, bool original_surface, + su2double &Fuselage_Volume, su2double &Fuselage_WettedArea, + su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth, + su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth, + su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight, + su2double &Fuselage_MaxCurvature) {} + + /*! + * \brief A virtual member. + */ + virtual void Compute_Nacelle(CConfig *config, bool original_surface, + su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness, su2double &Nacelle_MaxMaxThickness, + su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord, + su2double &Nacelle_MinLERadius, su2double &Nacelle_MaxLERadius, + su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC, + su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist) {} + + /*! + * \brief A virtual member. + * \param[in] config - Definition of the particular problem. + */ + inline virtual void FindNormal_Neighbor(CConfig *config) {} + + /*! + * \brief A virtual member. + */ + inline virtual void SetGlobal_to_Local_Point() {} + + /*! + * \brief A virtual member. + * \param[in] val_ipoint - Global point. + * \return Local index that correspond with the global index. + */ + inline virtual long GetGlobal_to_Local_Point(unsigned long val_ipoint) const { return 0; } + + /*! + * \brief A virtual member. + * \param[in] val_ipoint - Global marker. + * \return Local marker that correspond with the global index. + */ + inline virtual unsigned short GetGlobal_to_Local_Marker(unsigned short val_imarker) const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of nodes in a simulation across all processors (including halos). + */ + inline virtual unsigned long GetGlobal_nPoint() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of nodes in a simulation across all processors (excluding halos). + */ + inline virtual unsigned long GetGlobal_nPointDomain() const { return 0; } + + /*! + * \brief A virtual member. + * \param[in] val_global_npoint - Global number of points in the mesh (excluding halos). + */ + inline virtual void SetGlobal_nPointDomain(unsigned long val_global_npoint) {} + + /*! + * \brief A virtual member. + * \return Total number of elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElem() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of elements in a simulation across all processors (excluding halos). + */ + inline virtual unsigned long GetGlobal_nElemDomain() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of line elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemLine() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of triangular elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemTria() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of quadrilateral elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemQuad() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of tetrahedral elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemTetr() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of hexahedral elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemHexa() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of prism elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemPris() const { return 0; } + + /*! + * \brief A virtual member. + * \return Total number of pyramid elements in a simulation across all processors. + */ + inline virtual unsigned long GetGlobal_nElemPyra() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of line elements. + */ + inline virtual unsigned long GetnElemLine() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of triangular elements. + */ + inline virtual unsigned long GetnElemTria() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of quadrilateral elements. + */ + inline virtual unsigned long GetnElemQuad() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of tetrahedral elements. + */ + inline virtual unsigned long GetnElemTetr() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of hexahedral elements. + */ + inline virtual unsigned long GetnElemHexa() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of prism elements. + */ + inline virtual unsigned long GetnElemPris() const { return 0; } + + /*! + * \brief A virtual member. + * \return Number of pyramid elements. + */ + inline virtual unsigned long GetnElemPyra() const { return 0; } + + /*! + * \brief Indentify geometrical planes in the mesh + */ + void SetGeometryPlanes(CConfig *config); + + /*! + * \brief Get geometrical planes in the mesh + */ + inline vector GetGeometryPlanes() const {return XCoordList;} + + /*! + * \brief Get x coords of geometrical planes in the mesh + */ + inline vector > GetXCoord() const {return Xcoord_plane;} + + /*! + * \brief Get y coords of geometrical planes in the mesh + */ + inline vector > GetYCoord() const {return Ycoord_plane;} + + /*! + * \brief Get z coords of geometrical planes in the mesh + */ + inline vector > GetZCoord() const {return Zcoord_plane;} + + /*! + * \brief Get all points on a geometrical plane in the mesh + */ + inline vector > GetPlanarPoints() const {return Plane_points;} + + /*! + * \brief Given arrays x[1..n] and y[1..n] containing a tabulated function, i.e., yi = f(xi), with + x1 < x2 < . . . < xN , and given values yp1 and ypn for the first derivative of the interpolating + function at points 1 and n, respectively, this routine returns an array y2[1..n] that contains + the second derivatives of the interpolating function at the tabulated points xi. If yp1 and/or + ypn are equal to 1 × 1030 or larger, the routine is signaled to set the corresponding boundary + condition for a natural spline, with zero second derivative on that boundary. + Numerical Recipes: The Art of Scientific Computing, Third Edition in C++. + */ + void SetSpline(vector &x, vector &y, unsigned long n, su2double yp1, su2double ypn, vector &y2); + + /*! + * \brief Given the arrays xa[1..n] and ya[1..n], which tabulate a function (with the xai’s in order), + and given the array y2a[1..n], which is the output from spline above, and given a value of + x, this routine returns a cubic-spline interpolated value y. + Numerical Recipes: The Art of Scientific Computing, Third Edition in C++. + * \return The interpolated value of for x. + */ + su2double GetSpline(vector &xa, vector &ya, vector &y2a, unsigned long n, su2double x); + + /*! + * \brief Compute the intersection between a segment and a plane. + * \param[in] Segment_P0 - Definition of the particular problem. + * \param[in] Segment_P1 - Definition of the particular problem. + * \param[in] Plane_P0 - Definition of the particular problem. + * \param[in] Plane_Normal - Definition of the particular problem. + * \param[in] Intersection - Definition of the particular problem. + * \return If the intersection has has been successful. + */ + bool SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, + su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp); + + /*! + * \brief Ray Intersects Triangle (Moller and Trumbore algorithm) + */ + bool RayIntersectsTriangle(su2double orig[3], su2double dir[3], + su2double vert0[3], su2double vert1[3], su2double vert2[3], + su2double *intersect); + + /*! + * \brief Segment Intersects Triangle + */ + bool SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], + su2double vert0[3], su2double vert1[3], su2double vert2[3]); + + /*! + * \brief Segment Intersects Line (for 2D FFD Intersection) + */ + bool SegmentIntersectsLine(su2double point0[2], su2double point1[2], su2double vert0[2], su2double vert1[2]); + + /*! + * \brief Register the coordinates of the mesh nodes. + * \param[in] config + */ + void RegisterCoordinates(CConfig *config); + + /*! + * \brief Register the coordinates of the mesh nodes as output. + * \param[in] config + */ + void RegisterOutput_Coordinates(CConfig *config); + + /*! + * \brief Update the multi-grid structure and the wall-distance. + * \param geometry_container - Geometrical definition. + * \param config - Config + */ + void UpdateGeometry(CGeometry **geometry_container, CConfig *config); + + /*! + * \brief Update the multi-grid structure for the customized boundary conditions + * \param geometry_container - Geometrical definition. + * \param config - Definition of the particular problem. + */ + void UpdateCustomBoundaryConditions(CGeometry **geometry_container, CConfig *config); + + /*! + * \brief A virtual member. + * \param config - Config + */ + inline virtual void SetSensitivity(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param config - Config + */ + inline virtual void ReadUnorderedSensitivity(CConfig *config) {} + + /*! + * \brief A virtual member. + * \param iPoint - Point + * \param iDim - Dimension + */ + inline virtual su2double GetSensitivity(unsigned long iPoint, unsigned short iDim) const {return 0.0;} + + /*! + * \brief A virtual member. + * \param iPoint - Point + * \param iDim - Dimension + * \param val - Value of the sensitivity + */ + inline virtual void SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual const su2double* GetAverageTurboNormal(unsigned short val_marker, unsigned short val_span) const { return nullptr; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual const su2double* GetAverageNormal(unsigned short val_marker, unsigned short val_span) const { return nullptr; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual su2double GetSpanArea(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual su2double GetTurboRadius(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual su2double GetAverageTangGridVel(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise inflow tangential velocity. + */ + inline virtual su2double GetTangGridVelIn(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise outflow tangential velocity. + */ + inline virtual su2double GetTangGridVelOut(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise inflow area. + */ + inline virtual su2double GetSpanAreaIn(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise outflow area. + */ + inline virtual su2double GetSpanAreaOut(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise inflow radius. + */ + inline virtual su2double GetTurboRadiusIn(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise outflow radius. + */ + inline virtual su2double GetTurboRadiusOut(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline virtual void SetTangGridVelIn(su2double value, unsigned short val_marker, unsigned short val_span) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline virtual void SetTangGridVelOut(su2double value, unsigned short val_marker, unsigned short val_span) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline virtual void SetSpanAreaIn(su2double value, unsigned short val_marker, unsigned short val_span) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline virtual void SetSpanAreaOut(su2double value, unsigned short val_marker, unsigned short val_span) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline virtual void SetTurboRadiusIn(su2double value, unsigned short val_marker, unsigned short val_span) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline virtual void SetTurboRadiusOut(su2double value, unsigned short val_marker, unsigned short val_span) {} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual unsigned long GetnTotVertexSpan(unsigned short val_marker, unsigned short val_span) const {return 0;} + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual su2double GetMinAngularCoord(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual su2double GetMaxAngularCoord(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual su2double GetMinRelAngularCoord(unsigned short val_marker, unsigned short val_span) const { return 0.0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline virtual const su2double* GetAverageGridVel(unsigned short val_marker, unsigned short val_span) const {return nullptr;} + + /*! + * \brief A virtual member. + * \param config - Config + */ + inline virtual void Check_Periodicity(CConfig *config) {} + + /*! + * \brief Get the value of the customized temperature at a specified vertex on a specified marker. + * \param[in] val_marker - Marker value + * \param[in] val_vertex - Boundary vertex value + */ + inline su2double GetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex) const { + return CustomBoundaryTemperature[val_marker][val_vertex]; + } + + /*! + * \brief Set the value of the customized temperature at a specified vertex on a specified marker. + * \param[in] val_marker - Marker value + * \param[in] val_vertex - Boundary vertex value + * \param[in] val_customBoundaryTemperature - Value of the temperature. + */ + inline void SetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex, su2double val_customBoundaryTemperature) { + CustomBoundaryTemperature[val_marker][val_vertex] = val_customBoundaryTemperature; + } + + /*! + * \brief Get the value of the customized normal heat flux at a specified vertex on a specified marker. + * \param[in] val_marker - Marker value + * \param[in] val_vertex - Boundary vertex value + */ + inline su2double GetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex) const { + return CustomBoundaryHeatFlux[val_marker][val_vertex]; + } + + /*! + * \brief Set the value of the customized normal heat flux at a specified vertex on a specified marker. + * \param[in] val_marker - Marker value + * \param[in] val_vertex - Boundary vertex value + * \param[in] val_customBoundaryHeatFlux - Value of the normal heat flux. + */ + inline void SetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex, su2double val_customBoundaryHeatFlux) { + CustomBoundaryHeatFlux[val_marker][val_vertex] = val_customBoundaryHeatFlux; + } + + /*! + * \brief Filter values given at the element CG by performing a weighted average over a radial neighbourhood. + * \param[in] filter_radius - Parameter defining the size of the neighbourhood. + * \param[in] kernels - Kernel types and respective parameter, size of vector defines number of filter recursions. + * \param[in] search_limit - Max degree of neighborhood considered for neighbor search, avoids excessive work in fine regions. + * \param[in] input_values - "Raw" values. + * \param[out] output_values - Filtered values. + */ + void FilterValuesAtElementCG(const vector &filter_radius, const vector > &kernels, + const unsigned short search_limit, const su2double *input_values, su2double *output_values) const; + + /*! + * \brief Build the global (entire mesh!) adjacency matrix for the elements in compressed format. + * Used by FilterValuesAtElementCG to search for geometrically close neighbours. + * \param[out] neighbour_start - i'th position stores the start position in "neighbour_idx" for the immediate + * neighbours of global element "i". Size nElemDomain+1 + * \param[out] neighbour_idx - Global index of the neighbours, mush be NULL on entry and free'd by calling function. + */ + void GetGlobalElementAdjacencyMatrix(vector &neighbour_start, long *&neighbour_idx) const; + + /*! + * \brief Get the neighbours of the global element in the first position of "neighbours" that are within "radius" of it. + * \param[in] iElem_global - Element of interest. + * \param[in] radius - Parameter defining the size of the neighbourhood. + * \param[in] search_limit - Maximum "logical radius" to consider, limits cost in refined regions, use 0 for unlimited. + * \param[in] neighbour_start - See GetGlobalElementAdjacencyMatrix. + * \param[in] neighbour_idx - See GetGlobalElementAdjacencyMatrix. + * \param[in] cg_elem - Global element centroid coordinates in row major format {x0,y0,x1,y1,...}. Size nDim*nElemDomain. + * \param[in,out] neighbours - The neighbours of iElem_global. + * \param[in,out] is_neighbor - Working vector of size nElemGlobal, MUST be all false on entry (if so, on exit it will be the same). + * \return true if the search was successful, i.e. not limited. + */ + bool GetRadialNeighbourhood(const unsigned long iElem_global, const passivedouble radius, size_t search_limit, + const vector &neighbour_start, const long *neighbour_idx, + const su2double *cg_elem, vector &neighbours, vector &is_neighbor) const; + + /*! + * \brief Compute and store the volume of the elements. + * \param[in] config - Problem configuration. + */ + void SetElemVolume(CConfig *config); + + /*! + * \brief Set the multigrid index for the current geometry object. + * \param[in] val_iMesh - Multigrid index for current geometry object. + */ + inline void SetMGLevel(unsigned short val_iMesh) { MGLevel = val_iMesh; } + + /*! + * \brief Get the multigrid index for the current geometry object. + * \return Multigrid index for current geometry object. + */ + inline unsigned short GetMGLevel(void) const { return MGLevel; } + + /*! + * \brief Compute and store the volume of the elements. + * \param[in] config - Problem configuration. + */ + void UpdateBoundaries(CConfig *config); + + /*! + * \brief A virtual member. + * \param config - Config + */ + inline virtual void ComputeMeshQualityStatistics(CConfig *config) {} + +}; + diff --git a/Common/include/geometry/CMultiGridGeometry.hpp b/Common/include/geometry/CMultiGridGeometry.hpp new file mode 100644 index 000000000000..6ae103fd40b1 --- /dev/null +++ b/Common/include/geometry/CMultiGridGeometry.hpp @@ -0,0 +1,173 @@ +/*! + * \file CMultiGridGeometry.hpp + * \brief Headers of the multigrid geometry class. + * \author F. Palacios, T. Economon + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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 "CGeometry.hpp" + +/*! + * \class CMultiGridGeometry + * \brief Class for defining the multigrid geometry, the main delicated part is the + * agglomeration stage, which is done in the declaration. + * \author F. Palacios + */ +class CMultiGridGeometry final : public CGeometry { + +public: + /*--- This is to suppress Woverloaded-virtual, omitting it has no negative impact. ---*/ + using CGeometry::SetVertex; + using CGeometry::SetMeshFile; + using CGeometry::SetControlVolume; + using CGeometry::SetBoundControlVolume; + using CGeometry::SetPoint_Connectivity; + + /*! + * \brief Constructor of the class. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iMesh - Level of the multigrid. + * \param[in] iZone - Current zone in the mesh. + */ + CMultiGridGeometry(CGeometry **geometry, CConfig *config_container, unsigned short iMesh); + + /*! + * \brief Destructor of the class. + */ + ~CMultiGridGeometry(void); + + /*! + * \brief Determine if a CVPoint van be agglomerated, if it have the same marker point as the seed. + * \param[in] CVPoint - Control volume to be agglomerated. + * \param[in] marker_seed - Marker of the seed. + * \param[in] fine_grid - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \return TRUE or FALSE depending if the control volume can be agglomerated. + */ + bool SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config); + + /*! + * \brief Determine if a can be agglomerated using geometrical criteria. + * \param[in] iPoint - Seed point. + * \param[in] fine_grid - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + bool GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config); + + /*! + * \brief Determine if a CVPoint van be agglomerated, if it have the same marker point as the seed. + * \param[in] Suitable_Indirect_Neighbors - List of Indirect Neighbours that can be agglomerated. + * \param[in] iPoint - Seed point. + * \param[in] Index_CoarseCV - Index of agglomerated point. + * \param[in] fine_grid - Geometrical definition of the problem. + */ + void SetSuitableNeighbors(vector *Suitable_Indirect_Neighbors, unsigned long iPoint, + unsigned long Index_CoarseCV, CGeometry *fine_grid); + + /*! + * \brief Set boundary vertex. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetVertex(CGeometry *geometry, CConfig *config) override; + + /*! + * \brief Set points which surround a point. + * \param[in] geometry - Geometrical definition of the problem. + */ + void SetPoint_Connectivity(CGeometry *geometry) override; + + /*! + * \brief Set the edge structure of the agglomerated control volume. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] action - Allocate or not the new elements. + */ + void SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) override; + + /*! + * \brief Mach the near field boundary condition. + * \param[in] config - Definition of the particular problem. + */ + void MatchNearField(CConfig *config) override; + + /*! + * \brief Mach the near field boundary condition. + * \param[in] config - Definition of the particular problem. + */ + void MatchActuator_Disk(CConfig *config) override; + + /*! + * \brief Mach the periodic boundary conditions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_periodic - Index of the first periodic face in a pair. + */ + void MatchPeriodic(CConfig *config, unsigned short val_periodic) override; + + /*! + * \brief Set boundary vertex structure of the agglomerated control volume. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] action - Allocate or not the new elements. + */ + void SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) override; + + /*! + * \brief Set a representative coordinates of the agglomerated control volume. + * \param[in] geometry - Geometrical definition of the problem. + */ + void SetCoord(CGeometry *geometry) override; + + /*! + * \brief Set a representative wall normal heat flux of the agglomerated control volume on a particular boundary marker. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_marker - Index of the boundary marker. + */ + void SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker) override; + + /*! + * \brief Set a representative wall temperature of the agglomerated control volume on a particular boundary marker. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] val_marker - Index of the boundary marker. + */ + void SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker) override; + + /*! + * \brief Set the grid velocity at each node in the coarse mesh level based + * on a restriction from a finer mesh. + * \param[in] fine_mesh - Geometry container for the finer mesh level. + * \param[in] config - Definition of the particular problem. + */ + void SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) override; + + /*! + * \brief Find and store the closest neighbor to a vertex. + * \param[in] config - Definition of the particular problem. + */ + void FindNormal_Neighbor(CConfig *config) override; + +}; + diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp new file mode 100644 index 000000000000..b2428e1b97d3 --- /dev/null +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -0,0 +1,1107 @@ +/*! + * \file CPhysicalGeometry.hpp + * \brief Headers of the physical geometry class used to read meshes from file. + * \author F. Palacios, T. Economon + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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 "CGeometry.hpp" +#include "../CMeshReaderFVM.hpp" + +/*! + * \class CPhysicalGeometry + * \brief Class for reading a defining the primal grid which is read from the grid file in .su2 or .cgns format. + * \author F. Palacios, T. Economon, J. Alonso + */ +class CPhysicalGeometry final : public CGeometry { + + map Global_to_Local_Point; /*!< \brief Global-local indexation for the points. */ + long *Local_to_Global_Point; /*!< \brief Local-global indexation for the points. */ + unsigned short *Local_to_Global_Marker; /*!< \brief Local to Global marker. */ + unsigned short *Global_to_Local_Marker; /*!< \brief Global to Local marker. */ + unsigned long *adj_counter; /*!< \brief Adjacency counter. */ + unsigned long **adjacent_elem; /*!< \brief Adjacency element list. */ + su2double* Sensitivity; /*!< \brief Vector holding the sensitivities at each point. */ + + vector > Neighbors; + map Color_List; + vector Marker_Tags; + unsigned long nLocal_Point, + nLocal_PointDomain, + nLocal_PointGhost, + nLocal_PointPeriodic, + nLocal_Elem, + nLocal_Bound_Elem, + nGlobal_Elem, + nGlobal_Bound_Elem, + nLocal_Line, + nLocal_BoundTria, + nLocal_BoundQuad, + nLinear_Line, + nLinear_BoundTria, + nLinear_BoundQuad, + nLocal_Tria, + nLocal_Quad, + nLocal_Tetr, + nLocal_Hexa, + nLocal_Pris, + nLocal_Pyra; + unsigned long nMarker_Global; + su2double *Local_Coords; + unsigned long *Local_Points; + unsigned long *Local_Colors; + unsigned long *Conn_Line; + unsigned long *Conn_BoundTria; + unsigned long *Conn_BoundQuad; + unsigned long *Conn_Line_Linear; + unsigned long *Conn_BoundTria_Linear; + unsigned long *Conn_BoundQuad_Linear; + unsigned long *Conn_Tria; + unsigned long *Conn_Quad; + unsigned long *Conn_Tetr; + unsigned long *Conn_Hexa; + unsigned long *Conn_Pris; + unsigned long *Conn_Pyra; + unsigned long *ID_Line; + unsigned long *ID_BoundTria; + unsigned long *ID_BoundQuad; + unsigned long *ID_Line_Linear; + unsigned long *ID_BoundTria_Linear; + unsigned long *ID_BoundQuad_Linear; + unsigned long *ID_Tria; + unsigned long *ID_Quad; + unsigned long *ID_Tetr; + unsigned long *ID_Hexa; + unsigned long *ID_Pris; + unsigned long *ID_Pyra; + unsigned long *Elem_ID_Line; + unsigned long *Elem_ID_BoundTria; + unsigned long *Elem_ID_BoundQuad; + unsigned long *Elem_ID_Line_Linear; + unsigned long *Elem_ID_BoundTria_Linear; + unsigned long *Elem_ID_BoundQuad_Linear; + +public: + /*--- This is to suppress Woverloaded-virtual, omitting it has no negative impact. ---*/ + using CGeometry::SetVertex; + using CGeometry::SetMeshFile; + using CGeometry::SetControlVolume; + using CGeometry::SetBoundControlVolume; + using CGeometry::SetPoint_Connectivity; + + /*! + * \brief Constructor of the class. + */ + CPhysicalGeometry(void); + + /*! + * \overload + * \brief Reads the geometry of the grid and adjust the boundary + * conditions with the configuration file. + * \param[in] config - Definition of the particular problem. + * \param[in] val_mesh_filename - Name of the file with the grid information. + * \param[in] val_format - Format 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. + */ + CPhysicalGeometry(CConfig *config, unsigned short val_iZone, unsigned short val_nZone); + + /*! + * \overload + * \brief Accepts a geometry container holding a linearly partitioned grid + * with coloring performed by ParMETIS, and this routine distributes + * the points and cells to all partitions based on the coloring. + * \param[in] geometry - Definition of the geometry container holding the initial linear partitions of the grid + coloring. + * \param[in] config - Definition of the particular problem. + */ + CPhysicalGeometry(CGeometry *geometry, CConfig *config); + + /*! + * \overload + * \brief Accepts a geometry container holding a linearly partitioned grid + * with coloring performed by ParMETIS, and this routine distributes + * the points and cells to all partitions based on the coloring. + * \param[in] geometry - Definition of the geometry container holding the initial linear partitions of the grid + coloring. + * \param[in] config - Definition of the particular problem. + */ + CPhysicalGeometry(CGeometry *geometry, CConfig *config, bool val_flag); + + /*! + * \brief Destructor of the class. + */ + ~CPhysicalGeometry(void); + + /*! + * \brief Distributes the coloring from ParMETIS so that each rank has complete information about the local grid points. + * \param[in] geometry - Definition of the geometry container holding the initial linear partitions of the grid + coloring. + * \param[in] config - Definition of the particular problem. + */ + void DistributeColoring(CConfig *config, CGeometry *geometry); + + /*! + * \brief Distribute the grid points, including ghost points, across all ranks based on a ParMETIS coloring. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + */ + void DistributePoints(CConfig *config, CGeometry *geometry); + + /*! + * \brief Distribute the connectivity for a single volume element type across all ranks based on a ParMETIS coloring. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] Elem_Type - VTK index of the element type being distributed. + */ + void DistributeVolumeConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type); + + /*! + * \brief Distribute the connectivity for a single surface element type in all markers across all ranks based on a ParMETIS coloring. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] Elem_Type - VTK index of the element type being distributed. + */ + void DistributeSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type); + + /*! + * \brief Broadcast the marker tags for all boundaries from the master rank to all other ranks. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + */ + void DistributeMarkerTags(CConfig *config, CGeometry *geometry); + + /*! + * \brief Partition the marker connectivity held on the master rank according to a linear partitioning. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] Elem_Type - VTK index of the element type being distributed. + */ + void PartitionSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type); + + /*! + * \brief Load the local grid points after partitioning (owned and ghost) into the geometry class objects. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + */ + void LoadPoints(CConfig *config, CGeometry *geometry); + + /*! + * \brief Load the local volume elements after partitioning (owned and ghost) into the geometry class objects. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + */ + void LoadVolumeElements(CConfig *config, CGeometry *geometry); + + /*! + * \brief Load the local surface elements after partitioning (owned and ghost) into the geometry class objects. + * \param[in] config - Definition of the particular problem. + * \param[in] geometry - Geometrical definition of the problem. + */ + void LoadSurfaceElements(CConfig *config, CGeometry *geometry); + + /*! + * \brief Routine to launch non-blocking sends and recvs amongst all processors. + * \param[in] bufSend - Buffer of data to be sent. + * \param[in] nElemSend - Array containing the number of elements to send to other processors in cumulative storage format. + * \param[in] sendReq - Array of MPI send requests. + * \param[in] bufRecv - Buffer of data to be received. + * \param[in] nElemSend - Array containing the number of elements to receive from other processors in cumulative storage format. + * \param[in] sendReq - Array of MPI recv requests. + * \param[in] countPerElem - Pieces of data per element communicated. + */ + void InitiateCommsAll(void *bufSend, + int *nElemSend, + SU2_MPI::Request *sendReq, + void *bufRecv, + int *nElemRecv, + SU2_MPI::Request *recvReq, + unsigned short countPerElem, + unsigned short commType); + + /*! + * \brief Routine to complete the set of non-blocking communications launched with InitiateComms() with MPI_Waitany(). + * \param[in] nSends - Number of sends to be completed. + * \param[in] sendReq - Array of MPI send requests. + * \param[in] nRecvs - Number of receives to be completed. + * \param[in] sendReq - Array of MPI recv requests. + */ + void CompleteCommsAll(int nSends, + SU2_MPI::Request *sendReq, + int nRecvs, + SU2_MPI::Request *recvReq); + + /*! + * \brief Routine to compute the initial linear partitioning offset counts and store in persistent data structures. + * \param[in] val_npoint_global - total number of grid points in the mesh. + */ + void PrepareOffsets(unsigned long val_npoint_global); + + /*! + * \brief Get the processor that owns the global numbering index based on the linear partitioning. + * \param[in] val_global_index - Global index for a point. + * \return Rank of the owner processor for the current point based on linear partitioning. + */ + unsigned long GetLinearPartition(unsigned long val_global_index); + + /*! + * \brief Routine to sort the adjacency for ParMETIS for graph partitioning in parallel. + * \param[in] config - Definition of the particular problem. + */ + void SortAdjacency(CConfig *config); + + /*! + * \brief Set the send receive boundaries of the grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_domain - Number of domains for parallelization purposes. + */ + void SetSendReceive(CConfig *config) override; + + /*! + * \brief Set the send receive boundaries of the grid. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] val_domain - Number of domains for parallelization purposes. + */ + void SetBoundaries(CConfig *config) override; + + /*! + * \brief Set the local index that correspond with the global numbering index. + */ + void SetGlobal_to_Local_Point() override; + + /*! + * \brief Get the local index that correspond with the global numbering index. + * \param[in] val_ipoint - Global point. + * \return Local index that correspond with the global index, -1 if not found on the current rank (process). + */ + inline long GetGlobal_to_Local_Point(unsigned long val_ipoint) const override { + auto it = Global_to_Local_Point.find(val_ipoint); + if (it != Global_to_Local_Point.cend()) + return it->second; + return -1; + } + + /*! + * \brief Get the local marker that correspond with the global marker. + * \param[in] val_ipoint - Global marker. + * \return Local marker that correspond with the global index. + */ + inline unsigned short GetGlobal_to_Local_Marker(unsigned short val_imarker) const override { + return Global_to_Local_Marker[val_imarker]; + } + + /*! + * \brief Reads 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_format - Format 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_Mesh_FVM(CConfig *config, 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, 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, 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. + * \param[in] mesh - mesh reader object containing the current zone data. + */ + void LoadLinearlyPartitionedPoints(CConfig *config, CMeshReaderFVM *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); + + /*! + * \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); + + /*! + * \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. + */ + void PrepareAdjacency(CConfig *config); + + /*! + * \brief Find repeated nodes between two elements to identify the common face. + * \param[in] first_elem - Identification of the first element. + * \param[in] second_elem - Identification of the second element. + * \param[in] face_first_elem - Index of the common face for the first element. + * \param[in] face_second_elem - Index of the common face for the second element. + * \return It provides 0 or 1 depending if there is a common face or not. + */ + bool FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, + unsigned short &face_second_elem) override; + + /*! + * \brief Computes the distance to the nearest no-slip wall for each grid node. + * \param[in] config - Definition of the particular problem. + */ + void ComputeWall_Distance(CConfig *config) override; + + /*! + * \brief Compute surface area (positive z-direction) for force coefficient non-dimensionalization. + * \param[in] config - Definition of the particular problem. + */ + void SetPositive_ZArea(CConfig *config) override; + + /*! + * \brief Set points which surround a point. + */ + void SetPoint_Connectivity(void) override; + + /*! + * \brief Set a renumbering using a Reverse Cuthill-McKee Algorithm + * \param[in] config - Definition of the particular problem. + */ + void SetRCM_Ordering(CConfig *config) override; + + /*! + * \brief Set elements which surround an element. + */ + void SetElement_Connectivity(void) override; + + /*! + * \brief Set the volume element associated to each boundary element. + */ + void SetBoundVolume(void) override; + + /*! + * \brief Set boundary vertex. + * \param[in] config - Definition of the particular problem. + */ + void SetVertex(CConfig *config) override; + + /*! + * \brief Set number of span wise level for turbomachinery computation. + * \param[in] config - Definition of the particular problem. + */ + void ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) override; + + /*! + * \brief Set turbo boundary vertex. + * \param[in] config - Definition of the particular problem. + */ + void SetTurboVertex(CConfig *config,unsigned short val_iZone, unsigned short marker_flag, bool allocate) override; + + /*! + * \brief update turbo boundary vertex. + * \param[in] config - Definition of the particular problem. + */ + void UpdateTurboVertex(CConfig *config,unsigned short val_iZone, unsigned short marker_flag) override; + + /*! + * \brief Set turbo boundary vertex. + * \param[in] config - Definition of the particular problem. + */ + void SetAvgTurboValue(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) override; + + /*! + * \brief Set turbo boundary vertex. + * \param[in] config - Definition of the particular problem. + */ + void GatherInOutAverageValues(CConfig *config, bool allocate) override; + + /*! + * \brief Set the center of gravity of the face, elements and edges. + */ + void SetCoord_CG(void) override; + + /*! + * \brief Set the edge structure of the control volume. + * \param[in] config - Definition of the particular problem. + * \param[in] action - Allocate or not the new elements. + */ + void SetControlVolume(CConfig *config, unsigned short action) override; + + /*! + * \brief Visualize the structure of the control volume(s). + * \param[in] config - Definition of the particular problem. + * \param[in] action - Allocate or not the new elements. + */ + void VisualizeControlVolume(CConfig *config, unsigned short action) override; + + /*! + * \brief Mach the near field boundary condition. + * \param[in] config - Definition of the particular problem. + */ + void MatchNearField(CConfig *config) override; + + /*! + * \brief Mach the near field boundary condition. + * \param[in] config - Definition of the particular problem. + */ + void MatchActuator_Disk(CConfig *config) override; + + /*! + * \brief Mach the periodic boundary conditions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_periodic - Index of the first periodic face in a pair. + */ + void MatchPeriodic(CConfig *config, unsigned short val_periodic) override; + + /*! + * \brief Set boundary vertex structure of the control volume. + * \param[in] config - Definition of the particular problem. + * \param[in] action - Allocate or not the new elements. + */ + void SetBoundControlVolume(CConfig *config, unsigned short action) override; + + /*! + * \brief Set the maximum cell-center to cell-center distance for CVs. + * \param[in] config - Definition of the particular problem. + */ + void SetMaxLength(CConfig* config) override; + + /*! + * \brief Set the Tecplot file. + * \param[in] config_filename - Name of the file where the Tecplot + * information is going to be stored. + * \param[in] new_file - Create a new file. + */ + void SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file) override; + + /*! + * \brief Set the output file for boundaries in Tecplot + * \param[in] config - Definition of the particular problem. + * \param[in] mesh_filename - Name of the file where the Tecplot + * information is going to be stored. + * \param[in] new_file - Create a new file. + */ + void SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) override; + + /*! + * \brief Check the volume element orientation. + * \param[in] config - Definition of the particular problem. + */ + void Check_IntElem_Orientation(CConfig *config) override; + + /*! + * \brief Check the volume element orientation. + * \param[in] config - Definition of the particular problem. + */ + void Check_BoundElem_Orientation(CConfig *config) override; + + /*! + * \brief Set the domains for grid grid partitioning using ParMETIS. + * \param[in] config - Definition of the particular problem. + */ + void SetColorGrid_Parallel(CConfig *config) override; + + /*! + * \brief Set the domains for FEM grid partitioning using ParMETIS. + * \param[in] config - Definition of the particular problem. + */ + void SetColorFEMGrid_Parallel(CConfig *config) override; + + /*! + * \brief Compute the weights of the FEM graph for ParMETIS. + * \param[in] config - Definition of the particular problem. + * \param[in] localFaces - Vector, which contains the element faces of this rank. + * \param[in] adjacency - Neighbors of the element. + * \param[in] mapExternalElemIDToTimeLevel - Map from the external element ID's to their time level + and number of DOFs. + * \param[out] vwgt - Weights of the vertices of the graph, i.e. the elements. + * \param[out] adjwgt - Weights of the edges of the graph. + */ + void ComputeFEMGraphWeights( + CConfig *config, + const vector &localFaces, + const vector > &adjacency, + const map &mapExternalElemIDToTimeLevel, + vector &vwgt, + vector > &adjwgt); + + /*! + * \brief Determine the donor elements for the boundary elements on viscous + wall boundaries when wall functions are used. + * \param[in] config - Definition of the particular problem. + */ + void DetermineDonorElementsWallFunctions(CConfig *config); + + /*! + * \brief Determine whether or not the Jacobians of the elements and faces + are constant and a length scale of the elements. + * \param[in] config - Definition of the particular problem. + */ + void DetermineFEMConstantJacobiansAndLenScale(CConfig *config); + + /*! + * \brief Determine the neighboring information for periodic faces of a FEM grid. + * \param[in] config - Definition of the particular problem. + * \param[in,out] localFaces - Vector, which contains the element faces of this rank. + */ + void DeterminePeriodicFacesFEMGrid(CConfig *config, + vector &localFaces); + + /*! + * \brief Determine the time level of the elements when time accurate local time stepping is employed. + * \param[in] config - Definition of the particular problem. + * \param[in] localFaces - Vector, which contains the element faces of this rank. + * \param[out] mapExternalElemIDToTimeLevel - Map from the external element ID's to their time level and number of DOFs. + */ + void DetermineTimeLevelElements(CConfig *config, + const vector &localFaces, + map &mapExternalElemIDToTimeLevel); + + /*! + * \brief Do an implicit smoothing of the grid coordinates. + * \param[in] val_nSmooth - Number of smoothing iterations. + * \param[in] val_smooth_coeff - Relaxation factor. + * \param[in] config - Definition of the particular problem. + */ + void SetCoord_Smoothing(unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) override; + + /*! + * \brief Write the .su2 file. + * \param[in] config - Definition of the particular problem. + * \param[in] val_mesh_out_filename - Name of the output file. + */ + void SetMeshFile(CConfig *config, string val_mesh_out_filename) override; + + /*! + * \brief Compute 3 grid quality metrics: orthogonality angle, dual cell aspect ratio, and dual cell volume ratio. + * \param[in] config - Definition of the particular problem. + */ + void ComputeMeshQualityStatistics(CConfig *config) override; + + /*! + * \brief Find and store the closest neighbor to a vertex. + * \param[in] config - Definition of the particular problem. + */ + void FindNormal_Neighbor(CConfig *config) override; + + /*! + * \brief Retrieve total number of nodes in a simulation across all processors (including halos). + * \return Total number of nodes in a simulation across all processors (including halos). + */ + inline unsigned long GetGlobal_nPoint(void) const override { return Global_nPoint; } + + /*! + * \brief Retrieve total number of nodes in a simulation across all processors (excluding halos). + * \return Total number of nodes in a simulation across all processors (excluding halos). + */ + inline unsigned long GetGlobal_nPointDomain(void) const override { return Global_nPointDomain; } + + /*! + * \brief Retrieve total number of elements in a simulation across all processors. + * \return Total number of elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElem(void) const override { return Global_nElem; } + + /*! + * \brief Retrieve total number of elements in a simulation across all processors (excluding halos). + * \return Total number of elements in a simulation across all processors (excluding halos). + */ + inline unsigned long GetGlobal_nElemDomain(void) const override { return Global_nElemDomain; } + + /*! + * \brief Retrieve total number of triangular elements in a simulation across all processors. + * \return Total number of line elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemLine(void) const override { return Global_nelem_edge; } + + /*! + * \brief Retrieve total number of triangular elements in a simulation across all processors. + * \return Total number of triangular elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemTria(void) const override { return Global_nelem_triangle; } + + /*! + * \brief Retrieve total number of quadrilateral elements in a simulation across all processors. + * \return Total number of quadrilateral elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemQuad(void) const override { return Global_nelem_quad; } + + /*! + * \brief Retrieve total number of tetrahedral elements in a simulation across all processors. + * \return Total number of tetrahedral elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemTetr(void) const override { return Global_nelem_tetra; } + + /*! + * \brief Retrieve total number of hexahedral elements in a simulation across all processors. + * \return Total number of hexahedral elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemHexa(void) const override { return Global_nelem_hexa; } + + /*! + * \brief Retrieve total number of prism elements in a simulation across all processors. + * \return Total number of prism elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemPris(void) const override { return Global_nelem_prism; } + + /*! + * \brief Retrieve total number of pyramid elements in a simulation across all processors. + * \return Total number of pyramid elements in a simulation across all processors. + */ + inline unsigned long GetGlobal_nElemPyra(void) const override { return Global_nelem_pyramid; } + + /*! + * \brief Get number of triangular elements. + * \return Number of line elements. + */ + inline unsigned long GetnElemLine(void) const override { return nelem_edge; } + + /*! + * \brief Get number of triangular elements. + * \return Number of triangular elements. + */ + inline unsigned long GetnElemTria(void) const override { return nelem_triangle; } + + /*! + * \brief Get number of quadrilateral elements. + * \return Number of quadrilateral elements. + */ + inline unsigned long GetnElemQuad(void) const override { return nelem_quad; } + + /*! + * \brief Get number of tetrahedral elements. + * \return Number of tetrahedral elements. + */ + inline unsigned long GetnElemTetr(void) const override { return nelem_tetra; } + + /*! + * \brief Get number of hexahedral elements. + * \return Number of hexahedral elements. + */ + inline unsigned long GetnElemHexa(void) const override { return nelem_hexa; } + + /*! + * \brief Get number of prism elements. + * \return Number of prism elements. + */ + inline unsigned long GetnElemPris(void) const override { return nelem_prism; } + + /*! + * \brief Get number of pyramid elements. + * \return Number of pyramid elements. + */ + inline unsigned long GetnElemPyra(void) const override { return nelem_pyramid; } + + /*! + * \brief Read the sensitivity from an input file. + * \param[in] config - Definition of the particular problem. + */ + void SetBoundSensitivity(CConfig *config) override; + + /*! + * \brief Compute the maximum thickness of an airfoil. + * \return Maximum thickness at a particular seccion. + */ + su2double Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the twist of an airfoil. + * \return Twist at a particular seccion. + */ + su2double Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the leading/trailing edge location of an airfoil. + */ + void Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, + su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the leading/trailing edge location of a fuselage. + */ + void Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, + su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the chord of an airfoil. + * \return Chord of an airfoil. + */ + su2double Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the chord of an airfoil. + * \return Chord of an airfoil. + */ + su2double Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the chord of an airfoil. + * \return Chord of an airfoil. + */ + su2double Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the chord of an airfoil. + * \return Chord of an airfoil. + */ + su2double Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the chord of an airfoil. + * \return Chord of an airfoil. + */ + su2double Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the thickness of an airfoil. + */ + su2double Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, su2double &ZLoc) override; + + /*! + * \brief Compute the area of an airfoil. + * \return Area of an airfoil. + */ + su2double Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the length of an airfoil. + * \return Area of an airfoil. + */ + su2double Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) override; + + /*! + * \brief Compute the dihedral of a wing. + * \return Dihedral at a particular seccion. + */ + su2double Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, + su2double *LeadingEdge_i, su2double *TrailingEdge_i) override; + + /*! + * \brief Compute the curvature of a wing. + */ + su2double Compute_Curvature(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, + su2double *LeadingEdge_i, su2double *TrailingEdge_i, + su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1) override; + + /*! + * \brief Evaluate geometrical parameters of a wing. + */ + void Compute_Wing(CConfig *config, bool original_surface, + su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, + su2double &Wing_MinChord, su2double &Wing_MaxChord, + su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius, + su2double &Wing_MinToC, su2double &Wing_MaxToC, + su2double &Wing_ObjFun_MinToC, su2double &Wing_MaxTwist, + su2double &Wing_MaxCurvature, su2double &Wing_MaxDihedral) override; + + /*! + * \brief Evaluate geometrical parameters of a wing. + */ + void Compute_Fuselage(CConfig *config, bool original_surface, + su2double &Fuselage_Volume, su2double &Fuselage_WettedArea, + su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth, + su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth, + su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight, + su2double &Fuselage_MaxCurvature) override; + + /*! + * \brief Evaluate geometrical parameters of a wing. + */ + void Compute_Nacelle(CConfig *config, bool original_surface, + su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness, su2double &Nacelle_MaxMaxThickness, + su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord, + su2double &Nacelle_MinLERadius, su2double &Nacelle_MaxLERadius, + su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC, + su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist) override; + + /*! + * \brief Read the sensitivity from adjoint solution file and store it. + * \param[in] config - Definition of the particular problem. + */ + void SetSensitivity(CConfig *config) override; + + /*! + * \brief Read the sensitivity from unordered ASCII adjoint solution file and store it. + * \param[in] config - Definition of the particular problem. + */ + void ReadUnorderedSensitivity(CConfig *config) override; + + /*! + * \brief Get the Sensitivity at a specific point. + * \param[in] iPoint - The point where to get the sensitivity. + * \param[in] iDim - The component of the dim. vector. + * \return The sensitivity at point iPoint and dim. iDim. + */ + inline su2double GetSensitivity(unsigned long iPoint, unsigned short iDim) const override { return Sensitivity[iPoint*nDim+iDim]; } + + /*! + * \brief Set the Sensitivity at a specific point. + * \param[in] iPoint - The point where to get the sensitivity. + * \param[in] iDim - The component of the dim. vector. + * \param[in] val - Value of the sensitivity. + */ + inline void SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val) override {Sensitivity[iPoint*nDim+iDim] = val;} + + /*! + * \brief Check the mesh for periodicity and deactivate multigrid if periodicity is found. + * \param[in] config - Definition of the particular problem. + */ + void Check_Periodicity(CConfig *config) override; + + /*! + * \brief Get the average normal at a specific span for a given marker in the turbomachinery reference of frame. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + * \return The span-wise averaged turbo normal. + */ + inline const su2double* GetAverageTurboNormal(unsigned short val_marker, unsigned short val_span) const override { + return AverageTurboNormal[val_marker][val_span]; + } + + /*! + * \brief Get the average normal at a specific span for a given marker. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + * \return The span-wise averaged normal. + */ + inline const su2double* GetAverageNormal(unsigned short val_marker, unsigned short val_span) const override { + return AverageNormal[val_marker][val_span]; + } + + /*! + * \brief Get the value of the total area for each span. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + * \return The span-wise area. + */ + inline su2double GetSpanArea(unsigned short val_marker, unsigned short val_span) const override { + return SpanArea[val_marker][val_span]; + } + + /*! + * \brief Get the value of the total area for each span. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + * \return The span-wise averaged turbo normal. + */ + inline su2double GetTurboRadius(unsigned short val_marker, unsigned short val_span) const override { + return TurboRadius[val_marker][val_span]; + } + + /*! + * \brief Get the value of the average tangential rotational velocity for each span. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + * \return The span-wise averaged tangential velocity. + */ + inline su2double GetAverageTangGridVel(unsigned short val_marker, unsigned short val_span) const override { + return AverageTangGridVel[val_marker][val_span]; + } + + /*! + * \brief Get the value of the inflow tangential velocity at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise inflow tangential velocity. + */ + inline su2double GetTangGridVelIn(unsigned short val_marker, unsigned short val_span) const override { + return TangGridVelIn[val_marker][val_span]; + } + + /*! + * \brief Get the value of the outflow tangential velocity at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise outflow tangential velocity. + */ + inline su2double GetTangGridVelOut(unsigned short val_marker, unsigned short val_span) const override { + return TangGridVelOut[val_marker][val_span]; + } + + /*! + * \brief Get the value of the inflow area at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise inflow area. + */ + inline su2double GetSpanAreaIn(unsigned short val_marker, unsigned short val_span) const override { + return SpanAreaIn[val_marker][val_span]; + } + + /*! + * \brief Get the value of the outflow area at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise outflow area. + */ + inline su2double GetSpanAreaOut(unsigned short val_marker, unsigned short val_span) const override { + return SpanAreaOut[val_marker][val_span]; + } + + /*! + * \brief Get the value of the inflow radius at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise inflow radius. + */ + inline su2double GetTurboRadiusIn(unsigned short val_marker, unsigned short val_span) const override { + return TurboRadiusIn[val_marker][val_span]; + } + + /*! + * \brief Get the value of the outflow radius at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + * \return The span-wise outflow radius. + */ + inline su2double GetTurboRadiusOut(unsigned short val_marker, unsigned short val_span) const override { + return TurboRadiusOut[val_marker][val_span]; + } + + /*! + * \brief Set the value of the inflow tangential velocity at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline void SetTangGridVelIn(su2double value, unsigned short val_marker, unsigned short val_span) override { + TangGridVelIn[val_marker][val_span] = value; + } + + /*! + * \brief Set the value of the outflow tangential velocity at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline void SetTangGridVelOut(su2double value, unsigned short val_marker, unsigned short val_span) override { + TangGridVelOut[val_marker][val_span] = value; + } + + /*! + * \brief Get the value of the inflow area at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline void SetSpanAreaIn(su2double value, unsigned short val_marker, unsigned short val_span) override { + SpanAreaIn[val_marker][val_span] = value; + } + + /*! + * \brief Set the value of the outflow area at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline void SetSpanAreaOut(su2double value, unsigned short val_marker, unsigned short val_span) override { + SpanAreaOut[val_marker][val_span] = value; + } + + /*! + * \brief Set the value of the inflow radius at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline void SetTurboRadiusIn(su2double value, unsigned short val_marker, unsigned short val_span) override { + TurboRadiusIn[val_marker][val_span] = value; + } + + /*! + * \brief Set the value of the outflow radius at each span. + * \param[in] val_marker - marker turbo-performance value. + * \param[in] val_span - span value. + */ + inline void SetTurboRadiusOut(su2double value, unsigned short val_marker, unsigned short val_span) override { + TurboRadiusOut[val_marker][val_span] = value; + } + + /*! + * \brief A total number of vertex independently from the MPI partions. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline unsigned long GetnTotVertexSpan(unsigned short val_marker, unsigned short val_span) const override { + return nTotVertexSpan[val_marker][val_span]; + } + + /*! + * \brief min angular pitch independently from the MPI partions. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline su2double GetMinAngularCoord(unsigned short val_marker, unsigned short val_span) const override { + return MinAngularCoord[val_marker][val_span]; + } + + /*! + * \brief max angular pitch independently from the MPI partions. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline su2double GetMaxAngularCoord(unsigned short val_marker, unsigned short val_span) const override { + return MaxAngularCoord[val_marker][val_span]; + } + + /*! + * \brief min Relatice angular coord independently from the MPI partions. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline su2double GetMinRelAngularCoord(unsigned short val_marker, unsigned short val_span) const override { + return MinRelAngularCoord[val_marker][val_span]; + } + + /*! + * \brief Get the average grid velocity at a specific span for a given marker. + * \param[in] val_marker - marker value. + * \param[in] val_span - span value. + */ + inline const su2double* GetAverageGridVel(unsigned short val_marker, unsigned short val_span) const override { + return AverageGridVel[val_marker][val_span]; + } + +}; + diff --git a/Common/include/geometry_structure.hpp b/Common/include/geometry_structure.hpp deleted file mode 100644 index 32a1890ebefe..000000000000 --- a/Common/include/geometry_structure.hpp +++ /dev/null @@ -1,3012 +0,0 @@ -/*! - * \file geometry_structure.hpp - * \brief Headers of the main subroutines for creating the geometrical structure. - * The subroutines and functions are in the geometry_structure.cpp file. - * \author F. Palacios, T. Economon - * \version 7.0.0 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2019, 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 "./mpi_structure.hpp" - -#ifdef HAVE_METIS -#include "metis.h" -#endif -#ifdef HAVE_PARMETIS -extern "C" { -#include "parmetis.h" -} -#endif -#ifdef HAVE_CGNS -#include "fem_cgns_elements.hpp" -#endif -#include -#include -#include -#include -#include -#include -#include -#include -#include - -#include "primal_grid_structure.hpp" -#include "dual_grid_structure.hpp" -#include "config_structure.hpp" -#include "fem_standard_element.hpp" -#include "CMeshReaderFVM.hpp" - -using namespace std; - -/*! - * \class CUnsignedLong2T - * \brief Help class used to store two unsigned longs as one entity. - */ -class CUnsignedLong2T { -public: - unsigned long long0; /*!< \brief First long to store in this class. */ - unsigned long long1; /*!< \brief Second long to store in this class. */ - - /* Constructors and destructors. */ - CUnsignedLong2T(); - ~CUnsignedLong2T(); - - CUnsignedLong2T(const unsigned long a, const unsigned long b); - - CUnsignedLong2T(const CUnsignedLong2T &other); - - /* Operators. */ - CUnsignedLong2T& operator=(const CUnsignedLong2T &other); - - bool operator<(const CUnsignedLong2T &other) const; - - bool operator==(const CUnsignedLong2T &other) const; - -private: - /* Copy function. */ - void Copy(const CUnsignedLong2T &other); -}; - -/*! - * \class CUnsignedShort2T - * \brief Help class used to store two unsigned shorts as one entity. - */ -class CUnsignedShort2T { -public: - unsigned short short0; /*!< \brief First short to store in this class. */ - unsigned short short1; /*!< \brief Second short to store in this class. */ - - /* Constructors and destructors. */ - CUnsignedShort2T(); - ~CUnsignedShort2T(); - - CUnsignedShort2T(const unsigned short a, const unsigned short b); - - CUnsignedShort2T(const CUnsignedShort2T &other); - - /* Operators. */ - CUnsignedShort2T& operator=(const CUnsignedShort2T &other); - - bool operator<(const CUnsignedShort2T &other) const; - - bool operator==(const CUnsignedShort2T &other) const; - -private: - /* Copy function. */ - void Copy(const CUnsignedShort2T &other); -}; - -/*! - * \class CFaceOfElement - * \brief Class used in the partitioning of the FEM grid as well as the building of - the faces of DG. It stores a face of an element. - */ -class CFaceOfElement { -public: - unsigned short nCornerPoints; /*!< \brief Number of corner points of the face. */ - unsigned long cornerPoints[4]; /*!< \brief Global ID's of ther corner points. */ - unsigned long elemID0, elemID1; /*!< \brief Element ID's to the left and right. */ - unsigned short nPolyGrid0, nPolyGrid1; /*!< \brief Polynomial degrees of the grid of the elements - to the left and right. */ - unsigned short nPolySol0, nPolySol1; /*!< \brief Polynomial degrees of the solution of the elements - to the left and right. */ - unsigned short nDOFsElem0, nDOFsElem1; /*!< \brief Number of DOFs of the elements to the left and right. */ - unsigned short elemType0, elemType1; /*!< \brief Type of the elements to the left and right. */ - unsigned short faceID0, faceID1; /*!< \brief The local face ID in the corresponding elements - to the left and right of the face. */ - unsigned short periodicIndex; /*!< \brief Periodic indicator of the face. A value of 0 means no - periodic face. A value larger than 0 gives the index of - the periodic boundary + 1. */ - unsigned short periodicIndexDonor; /*!< \brief Periodic indicator of the donor face. A value of 0 means no - periodic donor face. A value larger than 0 gives the index of - the periodic donor boundary + 1. */ - short faceIndicator; /*!< \brief The corresponding boundary marker if this face is on a - boundary. For an internal face the value is -1, - while an invalidated face has the value -2. */ - bool JacFaceIsConsideredConstant; /*!< \brief Whether or not the Jacobian of the transformation - to the standard element is considered constant. */ - bool elem0IsOwner; /*!< \brief Whether or not the neighboring element 0 is the owner - of the face. If false, element 1 is the owner. */ - - /* Standard constructor and destructor. */ - CFaceOfElement(); - ~CFaceOfElement(){} - - /* Alternative constructor to set the corner points. */ - CFaceOfElement(const unsigned short VTK_Type, - const unsigned short nPoly, - const unsigned long *Nodes); - - /* Copy constructor and assignment operator. */ - CFaceOfElement(const CFaceOfElement &other); - - CFaceOfElement& operator=(const CFaceOfElement &other); - - /* Less than operator. Needed for the sorting and searching. */ - bool operator<(const CFaceOfElement &other) const; - - /* Equal operator. Needed for removing double entities. */ - bool operator ==(const CFaceOfElement &other) const; - - /*--- Member function, which creates a unique numbering for the corner points. - A sort in increasing order is OK for this purpose. ---*/ - void CreateUniqueNumbering(void); - - /*--- Member function, which creates a unique numbering for the corner points - while the orientation is taken into account. ---*/ - void CreateUniqueNumberingWithOrientation(void); - -private: - /*--- Copy function, which copies the data of the given object into the current object. ---*/ - void Copy(const CFaceOfElement &other); -}; - -/*! - * \class CBoundaryFace - * \brief Help class used in the partitioning of the FEM grid. - It stores a boundary element. - */ -class CBoundaryFace { -public: - unsigned short VTK_Type, nPolyGrid, nDOFsGrid; - unsigned long globalBoundElemID, domainElementID; - vector Nodes; - - /* Standard constructor and destructor. Nothing to be done. */ - CBoundaryFace(){} - ~CBoundaryFace(){} - - /* Copy constructor and assignment operator. */ - CBoundaryFace(const CBoundaryFace &other); - - CBoundaryFace& operator=(const CBoundaryFace &other); - - /* Less than operator. Needed for the sorting. */ - bool operator<(const CBoundaryFace &other) const; - -private: - /*--- Copy function, which copies the data of the given object into the current object. ---*/ - void Copy(const CBoundaryFace &other); -}; - -/*! - * \class CMatchingFace - * \brief Help class used to determine whether or not (periodic) faces match. - */ -class CMatchingFace { -public: - unsigned short nCornerPoints; /*!< \brief Number of corner points of the face. */ - unsigned short nDim; /*!< \brief Number of spatial dimensions. */ - unsigned short nPoly; /*!< \brief Polynomial degree of the face. */ - unsigned short nDOFsElem; /*!< \brief Number of DOFs of the relevant adjacent element. */ - unsigned short elemType; /*!< \brief Type of the adjacent element. */ - unsigned long elemID; /*!< \brief The relevant adjacent element ID. */ - su2double cornerCoor[4][3]; /*!< \brief Coordinates of the corner points of the face. */ - su2double tolForMatching; /*!< \brief Tolerance for this face for matching points. */ - - /* Standard constructor. */ - CMatchingFace(); - - /* Destructor, nothing to be done. */ - ~CMatchingFace(){} - - /* Copy constructor and assignment operator. */ - CMatchingFace(const CMatchingFace &other); - - CMatchingFace& operator=(const CMatchingFace &other); - - /* Less than operator. Needed for the sorting and searching. */ - bool operator<(const CMatchingFace &other) const; - - /*--- Member function, which sorts the coordinates of the face. ---*/ - void SortFaceCoordinates(void); - -private: - /*--- Copy function, which copies the data of the given object into the current object. ---*/ - void Copy(const CMatchingFace &other); -}; - -/*! - * \class CGeometry - * \brief Parent class for defining the geometry of the problem (complete geometry, - * multigrid agglomerated geometry, only boundary geometry, etc..) - * \author F. Palacios - */ -class CGeometry { -protected: - int rank, /*!< \brief MPI Rank. */ - size; /*!< \brief MPI Size. */ - unsigned long nPoint, /*!< \brief Number of points of the mesh. */ - nPointDomain, /*!< \brief Number of real points of the mesh. */ - nPointGhost, /*!< \brief Number of ghost points of the mesh. */ - nPointNode, /*!< \brief Size of the node array allocated to hold CPoint objects. */ - Global_nPoint, /*!< \brief Total number of nodes in a simulation across all processors (including halos). */ - Global_nPointDomain, /*!< \brief Total number of nodes in a simulation across all processors (excluding halos). */ - nElem, /*!< \brief Number of elements of the mesh. */ - Global_nElem, /*!< \brief Total number of elements in a simulation across all processors (all types). */ - Global_nElemDomain, /*!< \brief Total number of elements in a simulation across all processors (excluding halos). */ - nEdge, /*!< \brief Number of edges of the mesh. */ - nFace, /*!< \brief Number of faces of the mesh. */ - nelem_edge, /*!< \brief Number of edges in the mesh. */ - Global_nelem_edge, /*!< \brief Total number of edges in the mesh across all processors. */ - nelem_triangle, /*!< \brief Number of triangles in the mesh. */ - Global_nelem_triangle, /*!< \brief Total number of triangles in the mesh across all processors. */ - nelem_quad, /*!< \brief Number of quadrangles in the mesh. */ - Global_nelem_quad, /*!< \brief Total number of quadrangles in the mesh across all processors. */ - nelem_tetra, /*!< \brief Number of tetrahedra in the mesh. */ - Global_nelem_tetra, /*!< \brief Total number of tetrahedra in the mesh across all processors. */ - nelem_hexa, /*!< \brief Number of hexahedra in the mesh. */ - Global_nelem_hexa, /*!< \brief Total number of hexahedra in the mesh across all processors. */ - nelem_prism, /*!< \brief Number of prisms in the mesh. */ - Global_nelem_prism, /*!< \brief Total number of prisms in the mesh across all processors. */ - nelem_pyramid, /*!< \brief Number of pyramids in the mesh. */ - Global_nelem_pyramid, /*!< \brief Total number of pyramids in the mesh across all processors. */ - nelem_edge_bound, /*!< \brief Number of edges on the mesh boundaries. */ - Global_nelem_edge_bound, /*!< \brief Total number of edges on the mesh boundaries across all processors. */ - nelem_triangle_bound, /*!< \brief Number of triangles on the mesh boundaries. */ - Global_nelem_triangle_bound, /*!< \brief Total number of triangles on the mesh boundaries across all processors. */ - nelem_quad_bound, /*!< \brief Number of quads on the mesh boundaries. */ - Global_nelem_quad_bound; /*!< \brief Total number of quads on the mesh boundaries across all processors. */ - unsigned short nDim, /*!< \brief Number of dimension of the problem. */ - nZone, /*!< \brief Number of zones in the problem. */ - nMarker; /*!< \brief Number of different markers of the mesh. */ - unsigned short MGLevel; /*!< \brief The mesh level index for the current geometry container. */ - unsigned long Max_GlobalPoint; /*!< \brief Greater global point in the domain local structure. */ - - /* --- Custom boundary variables --- */ - su2double **CustomBoundaryTemperature; - su2double **CustomBoundaryHeatFlux; - -public: - unsigned long *nElem_Bound; /*!< \brief Number of elements of the boundary. */ - string *Tag_to_Marker; /*!< \brief If you know the index of the boundary (depend of the - grid definition), it gives you the maker (where the boundary - is stored from 0 to boundaries). */ - CPrimalGrid** elem; /*!< \brief Element vector (primal grid information). */ - CPrimalGrid** face; /*!< \brief Face vector (primal grid information). */ - CPrimalGrid*** bound; /*!< \brief Boundary vector (primal grid information). */ - CPoint** node; /*!< \brief Node vector (dual grid information). */ - CEdge** edge; /*!< \brief Edge vector (dual grid information). */ - CVertex*** vertex; /*!< \brief Boundary Vertex vector (dual grid information). */ - CTurboVertex**** turbovertex; /*!< \brief Boundary Vertex vector ordered for turbomachinery calculation(dual grid information). */ - unsigned long *nVertex; /*!< \brief Number of vertex for each marker. */ - vector bound_is_straight; /*!< \brief Bool if boundary-marker is straight(2D)/plane(3D) for each local marker. */ - unsigned short *nSpanWiseSections; /*!< \brief Number of Span wise section for each turbo marker, indexed by inflow/outflow */ - unsigned short *nSpanSectionsByMarker; /*!< \brief Number of Span wise section for each turbo marker, indexed by marker. Needed for deallocation.*/ - unsigned short nTurboPerf; /*!< \brief Number of Span wise section for each turbo marker. */ - su2double **SpanWiseValue; /*!< \brief Span wise values for each turbo marker. */ - long **nVertexSpan; /*!< \brief number of vertexes for span wise section for each marker. */ - unsigned long **nTotVertexSpan; /*!< \brief number of vertexes at each span wise section for each marker. */ - unsigned long nVertexSpanMax[3]; /*!< \brief max number of vertexes for each span section for each marker flag. */ - su2double ***AverageTurboNormal; /*!< \brief Average boundary normal at each span wise section for each marker in the turbomachinery frame of reference.*/ - su2double ***AverageNormal; /*!< \brief Average boundary normal at each span wise section for each marker.*/ - su2double ***AverageGridVel; /*!< \brief Average boundary grid velocity at each span wise section for each marker.*/ - su2double **AverageTangGridVel; /*!< \brief Average tangential rotational speed at each span wise section for each marker.*/ - su2double **SpanArea; /*!< \brief Area at each span wise section for each marker.*/ - su2double **MaxAngularCoord; /*!< \brief Max angular pitch at each span wise section for each marker.*/ - su2double **MinAngularCoord; /*!< \brief Max angular pitch at each span wise section for each marker.*/ - su2double **MinRelAngularCoord; /*!< \brief Min relative angular coord at each span wise section for each marker.*/ - su2double **TurboRadius; /*!< \brief Radius at each span wise section for each marker.*/ - su2double **TangGridVelIn, - **TangGridVelOut; /*!< \brief Average tangential rotational speed at each span wise section for each turbomachinery marker.*/ - su2double **SpanAreaIn, - **SpanAreaOut; /*!< \brief Area at each span wise section for each turbomachinery marker.*/ - su2double **TurboRadiusIn, - **TurboRadiusOut; /*!< \brief Radius at each span wise section for each turbomachinery marker*/ - - unsigned short nCommLevel; /*!< \brief Number of non-blocking communication levels. */ - - short *Marker_All_SendRecv; /*!< \brief MPI Marker. */ - - /*--- Create vectors and distribute the values among the different planes queues ---*/ - vector > Xcoord_plane; /*!< \brief Vector containing x coordinates of new points appearing on a single plane */ - vector > Ycoord_plane; /*!< \brief Vector containing y coordinates of new points appearing on a single plane */ - vector > Zcoord_plane; /*!< \brief Vector containing z coordinates of new points appearing on a single plane */ - vector > FaceArea_plane; /*!< \brief Vector containing area/volume associated with new points appearing on a single plane */ - vector > Plane_points; /*!< \brief Vector containing points appearing on a single plane */ - - vector XCoordList; /*!< \brief Vector containing points appearing on a single plane */ - CPrimalGrid*** newBound; /*!< \brief Boundary vector for new periodic elements (primal grid information). */ - unsigned long *nNewElem_Bound; /*!< \brief Number of new periodic elements of the boundary. */ - - /*--- Partitioning-specific variables ---*/ - - map Global_to_Local_Elem; /*!< \brief Mapping of global to local index for elements. */ - unsigned long *beg_node; /*!< \brief Array containing the first node on each rank due to a linear partitioning by global index. */ - unsigned long *end_node; /*!< \brief Array containing the last node on each rank due to a linear partitioning by global index. */ - unsigned long *nPointLinear; /*!< \brief Array containing the total number of nodes on each rank due to a linear partioning by global index. */ - unsigned long *nPointCumulative; /*!< \brief Cumulative storage array containing the total number of points on all prior ranks in the linear partitioning. */ - -#ifdef HAVE_MPI -#ifdef HAVE_PARMETIS - vector< vector > adj_nodes; /*!< \brief Vector of vectors holding each node's adjacency during preparation for ParMETIS. */ - idx_t *adjacency; /*!< \brief Local adjacency array to be input into ParMETIS for partitioning (idx_t is a ParMETIS type defined in their headers). */ - idx_t *xadj; /*!< \brief Index array that points to the start of each node's adjacency in CSR format (needed to interpret the adjacency array). */ -#endif -#endif - - /*--- Data structures for point-to-point MPI communications. ---*/ - - int countPerPoint; /*!< \brief Maximum number of pieces of data sent per vertex in point-to-point comms. */ - int nP2PSend; /*!< \brief Number of sends during point-to-point comms. */ - int nP2PRecv; /*!< \brief Number of receives during point-to-point comms. */ - int *nPoint_P2PSend; /*!< \brief Data structure holding number of vertices for each send in point-to-point comms. */ - int *nPoint_P2PRecv; /*!< \brief Data structure holding number of vertices for each recv in point-to-point comms. */ - int *Neighbors_P2PSend; /*!< \brief Data structure holding the ranks of the neighbors for point-to-point send comms. */ - int *Neighbors_P2PRecv; /*!< \brief Data structure holding the ranks of the neighbors for point-to-point recv comms. */ - map P2PSend2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for point-to-point send comms. */ - map P2PRecv2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for point-to-point recv comms. */ - unsigned long *Local_Point_P2PSend; /*!< \brief Data structure holding the local index of all vertices to be sent in point-to-point comms. */ - unsigned long *Local_Point_P2PRecv; /*!< \brief Data structure holding the local index of all vertices to be received in point-to-point comms. */ - su2double *bufD_P2PRecv; /*!< \brief Data structure for su2double point-to-point receive. */ - su2double *bufD_P2PSend; /*!< \brief Data structure for su2double point-to-point send. */ - unsigned short *bufS_P2PRecv; /*!< \brief Data structure for unsigned long point-to-point receive. */ - unsigned short *bufS_P2PSend; /*!< \brief Data structure for unsigned long point-to-point send. */ - SU2_MPI::Request *req_P2PSend; /*!< \brief Data structure for point-to-point send requests. */ - SU2_MPI::Request *req_P2PRecv; /*!< \brief Data structure for point-to-point recv requests. */ - - /*--- Data structures for periodic communications. ---*/ - - int countPerPeriodicPoint; /*!< \brief Maximum number of pieces of data sent per vertex in periodic comms. */ - int nPeriodicSend; /*!< \brief Number of sends during periodic comms. */ - int nPeriodicRecv; /*!< \brief Number of receives during periodic comms. */ - int *nPoint_PeriodicSend; /*!< \brief Data structure holding number of vertices for each send in periodic comms. */ - int *nPoint_PeriodicRecv; /*!< \brief Data structure holding number of vertices for each recv in periodic comms. */ - int *Neighbors_PeriodicSend; /*!< \brief Data structure holding the ranks of the neighbors for periodic send comms. */ - int *Neighbors_PeriodicRecv; /*!< \brief Data structure holding the ranks of the neighbors for periodic recv comms. */ - map PeriodicSend2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for periodic send comms. */ - map PeriodicRecv2Neighbor; /*!< \brief Data structure holding the reverse mapping of the ranks of the neighbors for periodic recv comms. */ - unsigned long *Local_Point_PeriodicSend; /*!< \brief Data structure holding the local index of all vertices to be sent in periodic comms. */ - unsigned long *Local_Point_PeriodicRecv; /*!< \brief Data structure holding the local index of all vertices to be received in periodic comms. */ - unsigned long *Local_Marker_PeriodicSend; /*!< \brief Data structure holding the local index of the periodic marker for a particular vertex to be sent in periodic comms. */ - unsigned long *Local_Marker_PeriodicRecv; /*!< \brief Data structure holding the local index of the periodic marker for a particular vertex to be received in periodic comms. */ - su2double *bufD_PeriodicRecv; /*!< \brief Data structure for su2double periodic receive. */ - su2double *bufD_PeriodicSend; /*!< \brief Data structure for su2double periodic send. */ - unsigned short *bufS_PeriodicRecv; /*!< \brief Data structure for unsigned long periodic receive. */ - unsigned short *bufS_PeriodicSend; /*!< \brief Data structure for unsigned long periodic send. */ - SU2_MPI::Request *req_PeriodicSend; /*!< \brief Data structure for periodic send requests. */ - SU2_MPI::Request *req_PeriodicRecv; /*!< \brief Data structure for periodic recv requests. */ - - vector Orthogonality; /*!< \brief Measure of dual CV orthogonality angle (0 to 90 deg., 90 being best). */ - vector Aspect_Ratio; /*!< \brief Measure of dual CV aspect ratio (max face area / min face area). */ - vector Volume_Ratio; /*!< \brief Measure of dual CV volume ratio (max sub-element volume / min sub-element volume). */ - - /*! - * \brief Constructor of the class. - */ - CGeometry(void); - - /*! - * \brief Constructor of the class. - */ - CGeometry(CConfig *config, unsigned short nDim); - - /*! - * \brief Destructor of the class. - */ - virtual ~CGeometry(void); - - /*! - * \brief Routine to launch non-blocking recvs only for all periodic communications. Note that this routine is called by any class that has loaded data into the generic communication buffers. - * \brief Routine to set up persistent data structures for point-to-point MPI communications. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void PreprocessP2PComms(CGeometry *geometry, CConfig *config); - - /*! - * \brief Routine to allocate buffers for point-to-point MPI communications. Also called to dynamically reallocate if not enough memory is found for comms during runtime. - * \param[in] val_countPerPoint - Maximum count of the data type per vertex in point-to-point comms, e.g., nPrimvarGrad*nDim. - */ - void AllocateP2PComms(unsigned short val_countPerPoint); - - /*! - * \brief Routine to launch non-blocking recvs only for all point-to-point communication with neighboring partitions. Note that this routine is called by any class that has loaded data into the generic communication buffers. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] commType - Enumerated type for the quantity to be communicated. - * \param[in] val_reverse - Boolean controlling forward or reverse communication between neighbors. - */ - void PostP2PRecvs(CGeometry *geometry, CConfig *config, unsigned short commType, bool val_reverse); - - /*! - * \brief Routine to launch a single non-blocking send once the buffer is loaded for a point-to-point commucation. Note that this routine is called by any class that has loaded data into the generic communication buffers. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] commType - Enumerated type for the quantity to be communicated. - * \param[in] val_iMessage - Index of the message in the order they are stored. - * \param[in] val_reverse - Boolean controlling forward or reverse communication between neighbors. - */ - void PostP2PSends(CGeometry *geometry, CConfig *config, unsigned short commType, int val_iMessage, bool val_reverse); - - /*! - * \brief Routine to set up persistent data structures for periodic communications. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void PreprocessPeriodicComms(CGeometry *geometry, CConfig *config); - - /*! - * \brief Routine to allocate buffers for periodic communications. Also called to dynamically reallocate if not enough memory is found for comms during runtime. - * \param[in] val_countPerPeriodicPoint - Maximum count of the data type per vertex in periodic comms, e.g., nPrimvarGrad*nDim. - */ - void AllocatePeriodicComms(unsigned short val_countPerPeriodicPoint); - - /*! - * \brief Routine to launch non-blocking recvs only for all periodic communication with neighboring partitions. Note that this routine is called by any class that has loaded data into the generic communication buffers. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] commType - Enumerated type for the quantity to be communicated. - */ - void PostPeriodicRecvs(CGeometry *geometry, CConfig *config, unsigned short commType); - - /*! - * \brief Routine to launch a single non-blocking send once the buffer is loaded for a periodic commucation. Note that this routine is called by any class that has loaded data into the generic communication buffers. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] commType - Enumerated type for the quantity to be communicated. - * \param[in] val_iMessage - Index of the message in the order they are stored. - */ - void PostPeriodicSends(CGeometry *geometry, CConfig *config, unsigned short commType, int val_iMessage); - - /*! - * \brief Routine to load a geometric quantity into the data structures for MPI point-to-point communication and to launch non-blocking sends and recvs for all point-to-point communication with neighboring partitions. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] commType - Enumerated type for the quantity to be communicated. - */ - void InitiateComms(CGeometry *geometry, CConfig *config, unsigned short commType); - - /*! - * \brief Routine to complete the set of non-blocking communications launched by InitiateComms() and unpacking of the data into the geometry class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] commType - Enumerated type for the quantity to be unpacked. - */ - void CompleteComms(CGeometry *geometry, CConfig *config, unsigned short commType); - - /*! - * \brief Get number of coordinates. - * \return Number of coordinates. - */ - unsigned short GetnDim(void); - - /*! - * \brief Get number of zones. - * \return Number of zones. - */ - unsigned short GetnZone(void); - - /*! - * \brief Get number of points. - * \return Number of points. - */ - unsigned long GetnPoint(void); - - /*! - * \brief Get number of real points (that belong to the domain). - * \return Number of real points. - */ - unsigned long GetnPointDomain(void); - - /*! - * \brief Get number of elements. - * \return Number of elements. - */ - unsigned long GetnLine(void); - - /*! - * \brief Get number of elements. - * \return Number of elements. - */ - unsigned long GetnElem(void); - - /*! - * \brief Get number of edges. - * \return Number of edges. - */ - unsigned long GetnEdge(void); - - /*! - * \brief Get number of markers. - * \return Number of markers. - */ - unsigned short GetnMarker(void); - - /*! - * \brief Get number of vertices. - * \param[in] val_marker - Marker of the boundary. - * \return Number of vertices. - */ - su2double* GetSpanWiseValue(unsigned short val_marker); - - /*! - * \brief Get number of vertices. - * \param[in] val_marker - Marker of the boundary. - * \return Number of vertices. - */ - unsigned long GetnVertex(unsigned short val_marker); - - /*! - * \brief Get number of span wise section. - * \param[in] marker_flag - flag of the turbomachinery boundary. - * \return Number of span wise section. - */ - unsigned short GetnSpanWiseSections(unsigned short marker_flag); - - /*! - * \brief Get number of vertices. - * \param[in] val_marker - Marker of the boundary. - * \return Number of vertices. - */ - unsigned long GetnVertexSpan(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get number of frequencies per span for NRBC. - * \param[in] val_marker - Marker of the boundary. - * \return Number of frequencies for NRBC. - */ - unsigned long GetnFreqSpan(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get number of vertices. - * \param[in] val_marker - Marker of the boundary. - * \return Number of vertices. - */ - unsigned long GetnVertexSpanMax(unsigned short marker_flag); - - /*! - * \brief Get number of max frequencies for initializing the Fourier Coefficient for NR BC. - * \param[in] marker_flag - Marker of the boundary. - * \return Number of frequencies. - */ - unsigned long GetnFreqSpanMax(unsigned short marker_flag); - - /*! - * \brief Get number of vertices. - * \param[in] val_marker - Marker of the boundary. - * \return Number of vertices. - */ - void SetnVertexSpanMax(unsigned short marker_flag, unsigned long nVertMax); - - /*! - * \brief Get the edge index from using the nodes of the edge. - * \param[in] first_point - First point of the edge. - * \param[in] second_point - Second point of the edge. - * \return Index of the edge. - */ - long FindEdge(unsigned long first_point, unsigned long second_point); - - /*! - * \brief Get the edge index from using the nodes of the edge. - * \param[in] first_point - First point of the edge. - * \param[in] second_point - Second point of the edge. - * \return Index of the edge. - */ - bool CheckEdge(unsigned long first_point, unsigned long second_point); - - /*! - * \brief Get the distance between a plane (defined by three point) and a point. - * \param[in] Coord - Coordinates of the point. - * \param[in] iCoord - Coordinates of the first point that defines the plane. - * \param[in] jCoord - Coordinates of the second point that defines the plane. - * \param[in] kCoord - Coordinates of the third point that defines the plane. - * \return Signed distance. - */ - su2double Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord); - - /*! - * \brief Create a file for testing the geometry. - */ - void TestGeometry(void); - - /*! - * \brief A virtual member. - * \param[in] val_nmarker - Number of markers. - */ - void SetnMarker(unsigned short val_nmarker); - - /*! - * \brief Set the number of dimensions of the problem. - * \param[in] val_nDim - Number of dimensions. - */ - void SetnDim(unsigned short val_nDim); - - /*! - * \brief Get the index of a marker. - * \param[in] val_marker - Marker of the boundary. - * \return Index of the marker in the grid defintion. - */ - string GetMarker_Tag(unsigned short val_marker); - - /*! - * \brief Set index of a marker. - * \param[in] val_marker - Marker of the boundary. - * \param[in] val_index - Index of the marker. - */ - void SetMarker_Tag(unsigned short val_marker, string val_index); - - /*! - * \brief Set the number of boundary elements. - * \param[in] val_marker - Marker of the boundary. - * \param[in] val_nelem_bound - Number of boundary elements. - */ - void SetnElem_Bound(unsigned short val_marker, unsigned long val_nelem_bound); - - /*! - * \brief Set the number of grid points. - * \param[in] val_npoint - Number of grid points. - */ - void SetnPoint(unsigned long val_npoint); - - /*! - * \brief Set the number of grid points in the domain. - * \param[in] val_npoint - Number of grid points in the domain. - */ - void SetnPointDomain(unsigned long val_npoint); - - /*! - * \brief Set the number of grid elements. - * \param[in] val_nelem - Number of grid elements. - */ - void SetnElem(unsigned long val_nelem); - - /*! - * \brief Get the number of boundary elements. - * \param[in] val_marker - Marker of the boundary. - */ - unsigned long GetnElem_Bound(unsigned short val_marker); - - /*! - * \brief Get the number of elements in vtk fortmat. - */ - unsigned long GetMax_GlobalPoint(void); - - /*! - * \brief Finds face of element. - * \param[in] first_elem - Identification of the first element. - * \param[in] second_elem - Identification of the second element. - * \param[in] face_first_elem - Index of the common face for the first element. - * \param[in] face_second_elem - Index of the common face for the second element. - */ - virtual bool FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, - unsigned short &face_second_elem); - - /*! - * \brief Computes the wall distance. - * \param[in] config - Definition of the particular problem. - */ - virtual void ComputeWall_Distance(CConfig *config); - - /*! - * \brief Sets area to be positive in Z direction. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetPositive_ZArea(CConfig *config); - - /*! - * \brief Setas connectivity between points. - */ - virtual void SetPoint_Connectivity(void); - - /*! - * \brief Orders the RCM. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetRCM_Ordering(CConfig *config); - - /*! - * \brief Connects elements . - */ - virtual void SetElement_Connectivity(void); - - /*! - * \brief Sets the edges of an elemment. - */ - void SetEdges(void); - - /*! - * \brief Sets the faces of an element.. - */ - virtual void SetFaces(void); - - /*! - * \brief Sets the boundary volume. - */ - virtual void SetBoundVolume(void); - - /*! - * \brief Sets the vertices. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetVertex(CConfig *config); - - /*! - * \brief Computes the N span. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Zone of the problem - * \param[in] marker_flag - Marker being used - * \param[in[ allocate - */ - virtual void ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate); - - /*! - * \brief Set vertices for turbomachinery problems. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Zone of the problem - * \param[in] marker_flag - Marker being used - * \param[in[ allocate - */ - virtual void SetTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Zone of the problem - * \param[in] marker_flag - Marker being used - */ - virtual void UpdateTurboVertex(CConfig *config, unsigned short val_iZone, unsigned short marker_flag); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Zone of the problem - * \param[in] marker_flag - Marker being used - * \param[in[ allocate - */ - virtual void SetAvgTurboValue(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] allocate - */ - virtual void GatherInOutAverageValues(CConfig *config, bool allocate); - - /*! - * \brief Sets vertex. - */ - virtual void SetVertex(void); - - /*! - * \brief Sets CG coordinates. - */ - virtual void SetCoord_CG(void); - - /*! - * \brief Set max length. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetMaxLength(CConfig* config); - - /*! - * \brief Sets control volume. - * \param[in] config - Definition of the particular problem. - * \param[in] action - Allocate or not the new elements. - */ - virtual void SetControlVolume(CConfig *config, unsigned short action); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] action - Allocate or not the new elements. - */ - virtual void VisualizeControlVolume(CConfig *config, unsigned short action); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void MatchNearField(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void MatchActuator_Disk(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void MatchPeriodic(CConfig *config, unsigned short val_periodic); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] action - Allocate or not the new elements. - */ - virtual void SetBoundControlVolume(CConfig *config, unsigned short action); - - /*! - * \brief A virtual member. - * \param[in] config_filename - Name of the file where the tecplot information is going to be stored. - */ - virtual void SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file); - - /*! - * \brief A virtual member. - * \param[in] mesh_filename - Name of the file where the tecplot information is going to be stored. - * \param[in] new_file - Boolean to decide if aopen a new file or add to a old one - * \param[in] config - Definition of the particular problem. - */ - virtual void SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void Check_IntElem_Orientation(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void Check_BoundElem_Orientation(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetColorGrid(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetColorGrid_Parallel(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetColorFEMGrid_Parallel(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void DivideConnectivity(CConfig *config, unsigned short Elem_Type); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_domain - Number of domains for parallelization purposes. - */ - virtual void SetSendReceive(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_domain - Number of domains for parallelization purposes. - */ - virtual void SetBoundaries(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - */ - virtual void SetCoord(CGeometry *geometry); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_marker - Index of the boundary marker. - */ - virtual void SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_marker - Index of the boundary marker. - */ - virtual void SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker); - - /*! - * \brief A virtual member. - * \param[in] val_nSmooth - Number of smoothing iterations. - * \param[in] val_smooth_coeff - Relaxation factor. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetCoord_Smoothing(unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - */ - virtual void SetPoint_Connectivity(CGeometry *geometry); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetVertex(CGeometry *geometry, CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] action - Allocate or not the new elements. - */ - virtual void SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] action - Allocate or not the new elements. - */ - virtual void SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] val_mesh_out_filename - Name of the output file. - */ - virtual void SetMeshFile(CConfig *config, string val_mesh_out_filename); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] val_mesh_out_filename - Name of the output file. - */ - virtual void SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetBoundSensitivity(CConfig *config); - - /*! - * \brief Set the data containers for customized boundary conditions. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetCustomBoundary(CConfig *config); - - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Index of the current zone. - */ - virtual void SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetShroudVelocity(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time step. - */ - virtual void SetGridVelocity(CConfig *config, unsigned long iter); - - /*! - * \brief A virtual member. - * \param[in] geometry - Geometry of the fine mesh. - * \param[in] config - Definition of the particular problem. - */ - virtual void SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config); - - /*! - * \brief Check if a boundary is straight(2D) / plane(3D) for EULER_WALL and SYMMETRY_PLANE - * only and store the information in bound_is_straight. For all other boundary types - * this will return false and could therfore be wrong. Used ultimately for BC_Slip_Wall. - * \param[in] config - Definition of the particular problem. - * \param[in] print_on_screen - Boolean whether to print result on screen. - */ - void ComputeSurf_Straightness(CConfig *config, - bool print_on_screen); - - /*! - * \brief Find and store all vertices on a sharp corner in the geometry. - * \param[in] config - Definition of the particular problem. - */ - void ComputeSurf_Curvature(CConfig *config); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - void ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, - su2double MinXCoord, su2double MaxXCoord, - su2double MinYCoord, su2double MaxYCoord, - su2double MinZCoord, su2double MaxZCoord, - su2double *FlowVariable, - vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, - vector &Zcoord_Airfoil, vector &Variable_Airfoil, - bool original_surface, CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, su2double &ZLoc); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual void Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector - &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual void Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector - &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, - su2double *LeadingEdge_i, su2double *TrailingEdge_i); - - /*! - * \brief A virtual member. - */ - virtual su2double Compute_Curvature(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, - su2double *LeadingEdge_i, su2double *TrailingEdge_i, - su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1); - - /*! - * \brief A virtual member. - */ - virtual void Compute_Wing(CConfig *config, bool original_surface, - su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, su2double &Wing_MinChord, su2double &Wing_MaxChord, - su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius, - su2double &Wing_MinToC, su2double &Wing_MaxToC, su2double &Wing_ObjFun_MinToC, su2double &Wing_MaxTwist, su2double &Wing_MaxCurvature, - su2double &Wing_MaxDihedral); - - /*! - * \brief A virtual member. - */ - virtual void Compute_Fuselage(CConfig *config, bool original_surface, - su2double &Fuselage_Volume, su2double &Fuselage_WettedArea, - su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth, - su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth, - su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight, - su2double &Fuselage_MaxCurvature); - - /*! - * \brief A virtual member. - */ - virtual void Compute_Nacelle(CConfig *config, bool original_surface, - su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness, su2double &Nacelle_MaxMaxThickness, - su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord, - su2double &Nacelle_MinLERadius, su2double &Nacelle_MaxLERadius, - su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC, - su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist); - - /*! - * \brief A virtual member. - * \param[in] config - Definition of the particular problem. - */ - virtual void FindNormal_Neighbor(CConfig *config); - - /*! - * \brief A virtual member. - */ - virtual void SetGlobal_to_Local_Point(); - - /*! - * \brief A virtual member. - * \param[in] val_ipoint - Global point. - * \returns Local index that correspond with the global index. - */ - virtual long GetGlobal_to_Local_Point(unsigned long val_ipoint); - - /*! - * \brief A virtual member. - * \param[in] val_ipoint - Global marker. - * \returns Local marker that correspond with the global index. - */ - virtual unsigned short GetGlobal_to_Local_Marker(unsigned short val_imarker); - - /*! - * \brief A virtual member. - * \returns Total number of nodes in a simulation across all processors (including halos). - */ - virtual unsigned long GetGlobal_nPoint(); - - /*! - * \brief A virtual member. - * \returns Total number of nodes in a simulation across all processors (excluding halos). - */ - virtual unsigned long GetGlobal_nPointDomain(); - - /*! - * \brief A virtual member. - * \param[in] val_global_npoint - Global number of points in the mesh (excluding halos). - */ - virtual void SetGlobal_nPointDomain(unsigned long val_global_npoint); - - /*! - * \brief A virtual member. - * \returns Total number of elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElem(); - - /*! - * \brief A virtual member. - * \returns Total number of elements in a simulation across all processors (excluding halos). - */ - virtual unsigned long GetGlobal_nElemDomain(); - - /*! - * \brief A virtual member. - * \returns Total number of line elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemLine(); - - /*! - * \brief A virtual member. - * \returns Total number of triangular elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemTria(); - - /*! - * \brief A virtual member. - * \returns Total number of quadrilateral elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemQuad(); - - /*! - * \brief A virtual member. - * \returns Total number of tetrahedral elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemTetr(); - - /*! - * \brief A virtual member. - * \returns Total number of hexahedral elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemHexa(); - - /*! - * \brief A virtual member. - * \returns Total number of prism elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemPris(); - - /*! - * \brief A virtual member. - * \returns Total number of pyramid elements in a simulation across all processors. - */ - virtual unsigned long GetGlobal_nElemPyra(); - - /*! - * \brief A virtual member. - * \return Number of line elements. - */ - virtual unsigned long GetnElemLine(); - - /*! - * \brief A virtual member. - * \return Number of triangular elements. - */ - virtual unsigned long GetnElemTria(); - - /*! - * \brief A virtual member. - * \return Number of quadrilateral elements. - */ - virtual unsigned long GetnElemQuad(); - - /*! - * \brief A virtual member. - * \return Number of tetrahedral elements. - */ - virtual unsigned long GetnElemTetr(); - - /*! - * \brief A virtual member. - * \return Number of hexahedral elements. - */ - virtual unsigned long GetnElemHexa(); - - /*! - * \brief A virtual member. - * \return Number of prism elements. - */ - virtual unsigned long GetnElemPris(); - - /*! - * \brief A virtual member. - * \return Number of pyramid elements. - */ - virtual unsigned long GetnElemPyra(); - - /*! - * \brief Indentify geometrical planes in the mesh - */ - virtual void SetGeometryPlanes(CConfig *config); - - /*! - * \brief Get geometrical planes in the mesh - */ - virtual vector GetGeometryPlanes(); - - /*! - * \brief Get x coords of geometrical planes in the mesh - */ - virtual vector > GetXCoord(); - - /*! - * \brief Get y coords of geometrical planes in the mesh - */ - virtual vector > GetYCoord(); - - /*! - * \brief Get z coords of geometrical planes in the mesh - */ - virtual vector > GetZCoord(); - - /*! - * \brief Get all points on a geometrical plane in the mesh - */ - virtual vector > GetPlanarPoints(); - - /*! - * \brief Given arrays x[1..n] and y[1..n] containing a tabulated function, i.e., yi = f(xi), with - x1 < x2 < . . . < xN , and given values yp1 and ypn for the first derivative of the interpolating - function at points 1 and n, respectively, this routine returns an array y2[1..n] that contains - the second derivatives of the interpolating function at the tabulated points xi. If yp1 and/or - ypn are equal to 1 × 1030 or larger, the routine is signaled to set the corresponding boundary - condition for a natural spline, with zero second derivative on that boundary. - Numerical Recipes: The Art of Scientific Computing, Third Edition in C++. - */ - void SetSpline(vector &x, vector &y, unsigned long n, su2double yp1, su2double ypn, vector &y2); - - /*! - * \brief Given the arrays xa[1..n] and ya[1..n], which tabulate a function (with the xai’s in order), - and given the array y2a[1..n], which is the output from spline above, and given a value of - x, this routine returns a cubic-spline interpolated value y. - Numerical Recipes: The Art of Scientific Computing, Third Edition in C++. - * \returns The interpolated value of for x. - */ - su2double GetSpline(vector &xa, vector &ya, vector &y2a, unsigned long n, su2double x); - - /*! - * \brief Compute the intersection between a segment and a plane. - * \param[in] Segment_P0 - Definition of the particular problem. - * \param[in] Segment_P1 - Definition of the particular problem. - * \param[in] Plane_P0 - Definition of the particular problem. - * \param[in] Plane_Normal - Definition of the particular problem. - * \param[in] Intersection - Definition of the particular problem. - * \returns If the intersection has has been successful. - */ - bool SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, - su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp); - - /*! - * \brief Ray Intersects Triangle (Moller and Trumbore algorithm) - */ - bool RayIntersectsTriangle(su2double orig[3], su2double dir[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3], - su2double *intersect); - - /*! - * \brief Segment Intersects Triangle - */ - bool SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3]); - - /*! - * \brief Segment Intersects Line (for 2D FFD Intersection) - */ - bool SegmentIntersectsLine(su2double point0[2], su2double point1[2], su2double vert0[2], su2double vert1[2]); - - /*! - * \brief Register the coordinates of the mesh nodes. - * \param[in] config - */ - void RegisterCoordinates(CConfig *config); - - /*! - * \brief Register the coordinates of the mesh nodes as output. - * \param[in] config - */ - void RegisterOutput_Coordinates(CConfig *config); - - /*! - * \brief Update the multi-grid structure and the wall-distance. - * \param geometry_container - Geometrical definition. - * \param config - Config - */ - void UpdateGeometry(CGeometry **geometry_container, CConfig *config); - - /*! - * \brief Update the multi-grid structure for the customized boundary conditions - * \param geometry_container - Geometrical definition. - * \param config - Definition of the particular problem. - */ - void UpdateCustomBoundaryConditions(CGeometry **geometry_container, CConfig *config); - - /*! - * \brief A virtual member. - * \param config - Config - */ - virtual void SetSensitivity(CConfig *config); - - /*! - * \brief A virtual member. - * \param config - Config - */ - virtual void ReadUnorderedSensitivity(CConfig *config); - - /*! - * \brief A virtual member. - * \param iPoint - Point - * \param iDim - Dimension - */ - virtual su2double GetSensitivity(unsigned long iPoint, unsigned short iDim); - - /*! - * \brief A virtual member. - * \param iPoint - Point - * \param iDim - Dimension - * \param val - Value of the sensitivity - */ - virtual void SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double* GetAverageTurboNormal(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double* GetAverageNormal(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double GetSpanArea(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double GetTurboRadius(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double GetAverageTangGridVel(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise inflow tangential velocity. - */ - virtual su2double GetTangGridVelIn(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise outflow tangential velocity. - */ - virtual su2double GetTangGridVelOut(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise inflow area. - */ - virtual su2double GetSpanAreaIn(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise outflow area. - */ - virtual su2double GetSpanAreaOut(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise inflow radius. - */ - virtual su2double GetTurboRadiusIn(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise outflow radius. - */ - virtual su2double GetTurboRadiusOut(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - virtual void SetTangGridVelIn(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - virtual void SetTangGridVelOut(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - virtual void SetSpanAreaIn(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - virtual void SetSpanAreaOut(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - virtual void SetTurboRadiusIn(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - virtual void SetTurboRadiusOut(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual unsigned long GetnTotVertexSpan(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double GetMinAngularCoord(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double GetMaxAngularCoord(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double GetMinRelAngularCoord(unsigned short val_marker, unsigned short val_span); - /*! - * \brief A virtual member. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - virtual su2double* GetAverageGridVel(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A virtual member. - * \param config - Config - */ - virtual void Check_Periodicity(CConfig *config); - - /*! - * \brief Get the value of the customized temperature at a specified vertex on a specified marker. - * \param[in] val_marker - Marker value - * \param[in] val_vertex - Boundary vertex value - */ - su2double GetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex); - - /*! - * \brief Set the value of the customized temperature at a specified vertex on a specified marker. - * \param[in] val_marker - Marker value - * \param[in] val_vertex - Boundary vertex value - * \param[in] val_customBoundaryTemperature - Value of the temperature. - */ - void SetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex, su2double val_customBoundaryTemperature); - - /*! - * \brief Get the value of the customized normal heat flux at a specified vertex on a specified marker. - * \param[in] val_marker - Marker value - * \param[in] val_vertex - Boundary vertex value - */ - su2double GetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex); - - /*! - * \brief Set the value of the customized normal heat flux at a specified vertex on a specified marker. - * \param[in] val_marker - Marker value - * \param[in] val_vertex - Boundary vertex value - * \param[in] val_customBoundaryHeatFlux - Value of the normal heat flux. - */ - void SetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex, su2double val_customBoundaryHeatFlux); - - /*! - * \brief Filter values given at the element CG by performing a weighted average over a radial neighbourhood. - * \param[in] filter_radius - Parameter defining the size of the neighbourhood. - * \param[in] kernels - Kernel types and respective parameter, size of vector defines number of filter recursions. - * \param[in] search_limit - Max degree of neighborhood considered for neighbor search, avoids excessive work in fine regions. - * \param[in] input_values - "Raw" values. - * \param[out] output_values - Filtered values. - */ - void FilterValuesAtElementCG(const vector &filter_radius, const vector > &kernels, - const unsigned short search_limit, const su2double *input_values, su2double *output_values) const; - - /*! - * \brief Build the global (entire mesh!) adjacency matrix for the elements in compressed format. - * Used by FilterValuesAtElementCG to search for geometrically close neighbours. - * \param[out] neighbour_start - i'th position stores the start position in "neighbour_idx" for the immediate - * neighbours of global element "i". Size nElemDomain+1 - * \param[out] neighbour_idx - Global index of the neighbours, mush be NULL on entry and free'd by calling function. - */ - void GetGlobalElementAdjacencyMatrix(vector &neighbour_start, long *&neighbour_idx) const; - - /*! - * \brief Get the neighbours of the global element in the first position of "neighbours" that are within "radius" of it. - * \param[in] iElem_global - Element of interest. - * \param[in] radius - Parameter defining the size of the neighbourhood. - * \param[in] search_limit - Maximum "logical radius" to consider, limits cost in refined regions, use 0 for unlimited. - * \param[in] neighbour_start - See GetGlobalElementAdjacencyMatrix. - * \param[in] neighbour_idx - See GetGlobalElementAdjacencyMatrix. - * \param[in] cg_elem - Global element centroid coordinates in row major format {x0,y0,x1,y1,...}. Size nDim*nElemDomain. - * \param[in,out] neighbours - The neighbours of iElem_global. - * \param[in,out] is_neighbor - Working vector of size nElemGlobal, MUST be all false on entry (if so, on exit it will be the same). - * \return true if the search was successful, i.e. not limited. - */ - bool GetRadialNeighbourhood(const unsigned long iElem_global, const passivedouble radius, size_t search_limit, - const vector &neighbour_start, const long *neighbour_idx, - const su2double *cg_elem, vector &neighbours, vector &is_neighbor) const; - - /*! - * \brief Compute and store the volume of the elements. - * \param[in] config - Problem configuration. - */ - void SetElemVolume(CConfig *config); - - /*! - * \brief Set the multigrid index for the current geometry object. - * \param[in] val_iMesh - Multigrid index for current geometry object. - */ - void SetMGLevel(unsigned short val_iMesh); - - /*! - * \brief Get the multigrid index for the current geometry object. - * \return Multigrid index for current geometry object. - */ - unsigned short GetMGLevel(void); - - /*! - * \brief Compute and store the volume of the elements. - * \param[in] config - Problem configuration. - */ - void UpdateBoundaries(CConfig *config); - - /*! - * \brief A virtual member. - * \param config - Config - */ - virtual void ComputeMeshQualityStatistics(CConfig *config); - -}; - -/*! - * \class CPhysicalGeometry - * \brief Class for reading a defining the primal grid which is read from the - * grid file in .su2 or .cgns format. - * \author F. Palacios, T. Economon, J. Alonso - */ -class CPhysicalGeometry : public CGeometry { - - map Global_to_Local_Point; /*!< \brief Global-local indexation for the points. */ - long *Local_to_Global_Point; /*!< \brief Local-global indexation for the points. */ - unsigned short *Local_to_Global_Marker; /*!< \brief Local to Global marker. */ - unsigned short *Global_to_Local_Marker; /*!< \brief Global to Local marker. */ - unsigned long *adj_counter; /*!< \brief Adjacency counter. */ - unsigned long **adjacent_elem; /*!< \brief Adjacency element list. */ - su2double* Sensitivity; /*! <\brief Vector holding the sensitivities at each point. */ - - vector > Neighbors; - map Color_List; - vector Marker_Tags; - unsigned long nLocal_Point, - nLocal_PointDomain, - nLocal_PointGhost, - nLocal_PointPeriodic, - nLocal_Elem, - nLocal_Bound_Elem, - nGlobal_Elem, - nGlobal_Bound_Elem, - nLocal_Line, - nLocal_BoundTria, - nLocal_BoundQuad, - nLinear_Line, - nLinear_BoundTria, - nLinear_BoundQuad, - nLocal_Tria, - nLocal_Quad, - nLocal_Tetr, - nLocal_Hexa, - nLocal_Pris, - nLocal_Pyra; - unsigned long nMarker_Global; - su2double *Local_Coords; - unsigned long *Local_Points; - unsigned long *Local_Colors; - unsigned long *Conn_Line; - unsigned long *Conn_BoundTria; - unsigned long *Conn_BoundQuad; - unsigned long *Conn_Line_Linear; - unsigned long *Conn_BoundTria_Linear; - unsigned long *Conn_BoundQuad_Linear; - unsigned long *Conn_Tria; - unsigned long *Conn_Quad; - unsigned long *Conn_Tetr; - unsigned long *Conn_Hexa; - unsigned long *Conn_Pris; - unsigned long *Conn_Pyra; - unsigned long *ID_Line; - unsigned long *ID_BoundTria; - unsigned long *ID_BoundQuad; - unsigned long *ID_Line_Linear; - unsigned long *ID_BoundTria_Linear; - unsigned long *ID_BoundQuad_Linear; - unsigned long *ID_Tria; - unsigned long *ID_Quad; - unsigned long *ID_Tetr; - unsigned long *ID_Hexa; - unsigned long *ID_Pris; - unsigned long *ID_Pyra; - unsigned long *Elem_ID_Line; - unsigned long *Elem_ID_BoundTria; - unsigned long *Elem_ID_BoundQuad; - unsigned long *Elem_ID_Line_Linear; - unsigned long *Elem_ID_BoundTria_Linear; - unsigned long *Elem_ID_BoundQuad_Linear; - -public: - - /*! - * \brief Constructor of the class. - */ - CPhysicalGeometry(void); - - /*! - * \overload - * \brief Reads the geometry of the grid and adjust the boundary - * conditions with the configuration file. - * \param[in] config - Definition of the particular problem. - * \param[in] val_mesh_filename - Name of the file with the grid information. - * \param[in] val_format - Format 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. - */ - CPhysicalGeometry(CConfig *config, unsigned short val_iZone, unsigned short val_nZone); - - /*! - * \overload - * \brief Accepts a geometry container holding a linearly partitioned grid - * with coloring performed by ParMETIS, and this routine distributes - * the points and cells to all partitions based on the coloring. - * \param[in] geometry - Definition of the geometry container holding the initial linear partitions of the grid + coloring. - * \param[in] config - Definition of the particular problem. - */ - CPhysicalGeometry(CGeometry *geometry, CConfig *config); - - /*! - * \overload - * \brief Accepts a geometry container holding a linearly partitioned grid - * with coloring performed by ParMETIS, and this routine distributes - * the points and cells to all partitions based on the coloring. - * \param[in] geometry - Definition of the geometry container holding the initial linear partitions of the grid + coloring. - * \param[in] config - Definition of the particular problem. - */ - CPhysicalGeometry(CGeometry *geometry, CConfig *config, bool val_flag); - - /*! - * \brief Destructor of the class. - */ - ~CPhysicalGeometry(void); - - /*! - * \brief Distributes the coloring from ParMETIS so that each rank has complete information about the local grid points. - * \param[in] geometry - Definition of the geometry container holding the initial linear partitions of the grid + coloring. - * \param[in] config - Definition of the particular problem. - */ - void DistributeColoring(CConfig *config, CGeometry *geometry); - - /*! - * \brief Distribute the grid points, including ghost points, across all ranks based on a ParMETIS coloring. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - */ - void DistributePoints(CConfig *config, CGeometry *geometry); - - /*! - * \brief Distribute the connectivity for a single volume element type across all ranks based on a ParMETIS coloring. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] Elem_Type - VTK index of the element type being distributed. - */ - void DistributeVolumeConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type); - - /*! - * \brief Distribute the connectivity for a single surface element type in all markers across all ranks based on a ParMETIS coloring. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] Elem_Type - VTK index of the element type being distributed. - */ - void DistributeSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type); - - /*! - * \brief Broadcast the marker tags for all boundaries from the master rank to all other ranks. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - */ - void DistributeMarkerTags(CConfig *config, CGeometry *geometry); - - /*! - * \brief Partition the marker connectivity held on the master rank according to a linear partitioning. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] Elem_Type - VTK index of the element type being distributed. - */ - void PartitionSurfaceConnectivity(CConfig *config, CGeometry *geometry, unsigned short Elem_Type); - - /*! - * \brief Load the local grid points after partitioning (owned and ghost) into the geometry class objects. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - */ - void LoadPoints(CConfig *config, CGeometry *geometry); - - /*! - * \brief Load the local volume elements after partitioning (owned and ghost) into the geometry class objects. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - */ - void LoadVolumeElements(CConfig *config, CGeometry *geometry); - - /*! - * \brief Load the local surface elements after partitioning (owned and ghost) into the geometry class objects. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - */ - void LoadSurfaceElements(CConfig *config, CGeometry *geometry); - - /*! - * \brief Routine to launch non-blocking sends and recvs amongst all processors. - * \param[in] bufSend - Buffer of data to be sent. - * \param[in] nElemSend - Array containing the number of elements to send to other processors in cumulative storage format. - * \param[in] sendReq - Array of MPI send requests. - * \param[in] bufRecv - Buffer of data to be received. - * \param[in] nElemSend - Array containing the number of elements to receive from other processors in cumulative storage format. - * \param[in] sendReq - Array of MPI recv requests. - * \param[in] countPerElem - Pieces of data per element communicated. - */ - void InitiateCommsAll(void *bufSend, - int *nElemSend, - SU2_MPI::Request *sendReq, - void *bufRecv, - int *nElemRecv, - SU2_MPI::Request *recvReq, - unsigned short countPerElem, - unsigned short commType); - - /*! - * \brief Routine to complete the set of non-blocking communications launched with InitiateComms() with MPI_Waitany(). - * \param[in] nSends - Number of sends to be completed. - * \param[in] sendReq - Array of MPI send requests. - * \param[in] nRecvs - Number of receives to be completed. - * \param[in] sendReq - Array of MPI recv requests. - */ - void CompleteCommsAll(int nSends, - SU2_MPI::Request *sendReq, - int nRecvs, - SU2_MPI::Request *recvReq); - - /*! - * \brief Routine to compute the initial linear partitioning offset counts and store in persistent data structures. - * \param[in] val_npoint_global - total number of grid points in the mesh. - */ - void PrepareOffsets(unsigned long val_npoint_global); - - /*! - * \brief Get the processor that owns the global numbering index based on the linear partitioning. - * \param[in] val_global_index - Global index for a point. - * \returns Rank of the owner processor for the current point based on linear partitioning. - */ - unsigned long GetLinearPartition(unsigned long val_global_index); - - /*! - * \brief Routine to sort the adjacency for ParMETIS for graph partitioning in parallel. - * \param[in] config - Definition of the particular problem. - */ - void SortAdjacency(CConfig *config); - - /*! - * \brief Set the send receive boundaries of the grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_domain - Number of domains for parallelization purposes. - */ - void SetSendReceive(CConfig *config); - - /*! - * \brief Set the send receive boundaries of the grid. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] val_domain - Number of domains for parallelization purposes. - */ - void SetBoundaries(CConfig *config); - - /*! - * \brief Set the local index that correspond with the global numbering index. - */ - void SetGlobal_to_Local_Point(); - - /*! - * \brief Get the local index that correspond with the global numbering index. - * \param[in] val_ipoint - Global point. - * \returns Local index that correspond with the global index, -1 if not found on the current rank (process). - */ - long GetGlobal_to_Local_Point(unsigned long val_ipoint); - - /*! - * \brief Get the local marker that correspond with the global marker. - * \param[in] val_ipoint - Global marker. - * \returns Local marker that correspond with the global index. - */ - unsigned short GetGlobal_to_Local_Marker(unsigned short val_imarker); - /*! - * \brief Reads 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_format - Format 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_Mesh_FVM(CConfig *config, 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, 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, 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. - * \param[in] mesh - mesh reader object containing the current zone data. - */ - void LoadLinearlyPartitionedPoints(CConfig *config, - CMeshReaderFVM *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); - - /*! - * \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); - - /*! - * \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. - */ - void PrepareAdjacency(CConfig *config); - - /*! - * \brief Find repeated nodes between two elements to identify the common face. - * \param[in] first_elem - Identification of the first element. - * \param[in] second_elem - Identification of the second element. - * \param[in] face_first_elem - Index of the common face for the first element. - * \param[in] face_second_elem - Index of the common face for the second element. - * \return It provides 0 or 1 depending if there is a common face or not. - */ - bool FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, - unsigned short &face_second_elem); - - /*! - * \brief Computes the distance to the nearest no-slip wall for each grid node. - * \param[in] config - Definition of the particular problem. - */ - void ComputeWall_Distance(CConfig *config); - - /*! - * \brief Compute surface area (positive z-direction) for force coefficient non-dimensionalization. - * \param[in] config - Definition of the particular problem. - */ - void SetPositive_ZArea(CConfig *config); - - /*! - * \brief Set points which surround a point. - */ - void SetPoint_Connectivity(void); - - /*! - * \brief Set a renumbering using a Reverse Cuthill-McKee Algorithm - * \param[in] config - Definition of the particular problem. - */ - void SetRCM_Ordering(CConfig *config); - - /*! - * \brief Function declaration to avoid partially overridden classes. - * \param[in] geometry - Geometrical definition of the problem. - */ - void SetPoint_Connectivity(CGeometry *geometry); - - /*! - * \brief Set elements which surround an element. - */ - void SetElement_Connectivity(void); - - /*! - * \brief Set the volume element associated to each boundary element. - */ - void SetBoundVolume(void); - - /*! - * \brief Set boundary vertex. - * \param[in] config - Definition of the particular problem. - */ - void SetVertex(CConfig *config); - - /*! - * \brief Set number of span wise level for turbomachinery computation. - * \param[in] config - Definition of the particular problem. - */ - void ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate); - - /*! - * \brief Set turbo boundary vertex. - * \param[in] config - Definition of the particular problem. - */ - void SetTurboVertex(CConfig *config,unsigned short val_iZone, unsigned short marker_flag, bool allocate); - - /*! - * \brief update turbo boundary vertex. - * \param[in] config - Definition of the particular problem. - */ - void UpdateTurboVertex(CConfig *config,unsigned short val_iZone, unsigned short marker_flag); - - /*! - * \brief Set turbo boundary vertex. - * \param[in] config - Definition of the particular problem. - */ - void SetAvgTurboValue(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate); - - /*! - * \brief Set turbo boundary vertex. - * \param[in] config - Definition of the particular problem. - */ - void GatherInOutAverageValues(CConfig *config, bool allocate); - - /*! - * \brief Set the center of gravity of the face, elements and edges. - */ - void SetCoord_CG(void); - - /*! - * \brief Set the edge structure of the control volume. - * \param[in] config - Definition of the particular problem. - * \param[in] action - Allocate or not the new elements. - */ - void SetControlVolume(CConfig *config, unsigned short action); - - /*! - * \brief Visualize the structure of the control volume(s). - * \param[in] config - Definition of the particular problem. - * \param[in] action - Allocate or not the new elements. - */ - void VisualizeControlVolume(CConfig *config, unsigned short action); - - /*! - * \brief Mach the near field boundary condition. - * \param[in] config - Definition of the particular problem. - */ - void MatchNearField(CConfig *config); - - /*! - * \brief Mach the near field boundary condition. - * \param[in] config - Definition of the particular problem. - */ - void MatchActuator_Disk(CConfig *config); - - /*! - * \brief Mach the periodic boundary conditions. - * \param[in] config - Definition of the particular problem. - * \param[in] val_periodic - Index of the first periodic face in a pair. - */ - void MatchPeriodic(CConfig *config, unsigned short val_periodic); - - /*! - * \brief Set boundary vertex structure of the control volume. - * \param[in] config - Definition of the particular problem. - * \param[in] action - Allocate or not the new elements. - */ - void SetBoundControlVolume(CConfig *config, unsigned short action); - - /*! - * \brief Set the maximum cell-center to cell-center distance for CVs. - * \param[in] config - Definition of the particular problem. - */ - void SetMaxLength(CConfig* config); - - /*! - * \brief Set the Tecplot file. - * \param[in] config_filename - Name of the file where the Tecplot - * information is going to be stored. - * \param[in] new_file - Create a new file. - */ - void SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file); - - /*! - * \brief Set the output file for boundaries in Tecplot - * \param[in] config - Definition of the particular problem. - * \param[in] mesh_filename - Name of the file where the Tecplot - * information is going to be stored. - * \param[in] new_file - Create a new file. - */ - void SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config); - - /*! - * \brief Check the volume element orientation. - * \param[in] config - Definition of the particular problem. - */ - void Check_IntElem_Orientation(CConfig *config); - - /*! - * \brief Check the volume element orientation. - * \param[in] config - Definition of the particular problem. - */ - void Check_BoundElem_Orientation(CConfig *config); - - /*! - * \brief Set the domains for grid grid partitioning using ParMETIS. - * \param[in] config - Definition of the particular problem. - */ - void SetColorGrid_Parallel(CConfig *config); - - /*! - * \brief Set the domains for FEM grid partitioning using ParMETIS. - * \param[in] config - Definition of the particular problem. - */ - void SetColorFEMGrid_Parallel(CConfig *config); - - /*! - * \brief Compute the weights of the FEM graph for ParMETIS. - * \param[in] config - Definition of the particular problem. - * \param[in] localFaces - Vector, which contains the element faces of this rank. - * \param[in] adjacency - Neighbors of the element. - * \param[in] mapExternalElemIDToTimeLevel - Map from the external element ID's to their time level - and number of DOFs. - * \param[out] vwgt - Weights of the vertices of the graph, i.e. the elements. - * \param[out] adjwgt - Weights of the edges of the graph. - */ - void ComputeFEMGraphWeights( - CConfig *config, - const vector &localFaces, - const vector > &adjacency, - const map &mapExternalElemIDToTimeLevel, - vector &vwgt, - vector > &adjwgt); - - /*! - * \brief Determine the donor elements for the boundary elements on viscous - wall boundaries when wall functions are used. - * \param[in] config - Definition of the particular problem. - */ - void DetermineDonorElementsWallFunctions(CConfig *config); - - /*! - * \brief Determine whether or not the Jacobians of the elements and faces - are constant and a length scale of the elements. - * \param[in] config - Definition of the particular problem. - */ - void DetermineFEMConstantJacobiansAndLenScale(CConfig *config); - - /*! - * \brief Determine the neighboring information for periodic faces of a FEM grid. - * \param[in] config - Definition of the particular problem. - * \param[in,out] localFaces - Vector, which contains the element faces of this rank. - */ - void DeterminePeriodicFacesFEMGrid(CConfig *config, - vector &localFaces); - - /*! - * \brief Determine the time level of the elements when time accurate - local time stepping is employed. - * \param[in] config - Definition of the particular problem. - * \param[in] localFaces - Vector, which contains the element - faces of this rank. - * \param[out] mapExternalElemIDToTimeLevel - Map from the external element ID's to - their time level and number of DOFs. - */ - void DetermineTimeLevelElements(CConfig *config, - const vector &localFaces, - map &mapExternalElemIDToTimeLevel); - - /*! - * \brief Set the rotational velocity at each node. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Index of the current zone. - */ - void SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print); - - /*! - * \brief Set the rotational velocity of the points on the shroud markers to 0. - * \param[in] config - Definition of the particular problem. - */ - void SetShroudVelocity(CConfig *config); - - /*! - * \brief Set the translational velocity at each node. - * \param[in] config - Definition of the particular problem. - */ - void SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print); - - /*! - * \brief Set the grid velocity via finite differencing at each node. - * \param[in] config - Definition of the particular problem. - */ - void SetGridVelocity(CConfig *config, unsigned long iter); - - /*! - * \brief Do an implicit smoothing of the grid coordinates. - * \param[in] val_nSmooth - Number of smoothing iterations. - * \param[in] val_smooth_coeff - Relaxation factor. - * \param[in] config - Definition of the particular problem. - */ - void SetCoord_Smoothing(unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config); - - /*! - * \brief Write the .su2 file. - * \param[in] config - Definition of the particular problem. - * \param[in] val_mesh_out_filename - Name of the output file. - */ - void SetMeshFile(CConfig *config, string val_mesh_out_filename); - - /*! - * \brief Compute 3 grid quality metrics: orthogonality angle, dual cell aspect ratio, and dual cell volume ratio. - * \param[in] config - Definition of the particular problem. - */ - void ComputeMeshQualityStatistics(CConfig *config); - - /*! - * \brief Find and store all vertices on a sharp corner in the geometry. - * \param[in] config - Definition of the particular problem. - */ - void ComputeSurf_Curvature(CConfig *config); - - /*! - * \brief Find and store the closest neighbor to a vertex. - * \param[in] config - Definition of the particular problem. - */ - void FindNormal_Neighbor(CConfig *config); - - /*! - * \brief Retrieve total number of nodes in a simulation across all processors (including halos). - * \returns Total number of nodes in a simulation across all processors (including halos). - */ - unsigned long GetGlobal_nPoint(); - - /*! - * \brief Retrieve total number of nodes in a simulation across all processors (excluding halos). - * \returns Total number of nodes in a simulation across all processors (excluding halos). - */ - unsigned long GetGlobal_nPointDomain(); - - /*! - * \brief Retrieve total number of elements in a simulation across all processors. - * \returns Total number of elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElem(); - - /*! - * \brief Retrieve total number of elements in a simulation across all processors (excluding halos). - * \returns Total number of elements in a simulation across all processors (excluding halos). - */ - unsigned long GetGlobal_nElemDomain(); - - /*! - * \brief Retrieve total number of triangular elements in a simulation across all processors. - * \returns Total number of line elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemLine(); - - /*! - * \brief Retrieve total number of triangular elements in a simulation across all processors. - * \returns Total number of triangular elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemTria(); - - /*! - * \brief Retrieve total number of quadrilateral elements in a simulation across all processors. - * \returns Total number of quadrilateral elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemQuad(); - - /*! - * \brief Retrieve total number of tetrahedral elements in a simulation across all processors. - * \returns Total number of tetrahedral elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemTetr(); - - /*! - * \brief Retrieve total number of hexahedral elements in a simulation across all processors. - * \returns Total number of hexahedral elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemHexa(); - - /*! - * \brief Retrieve total number of prism elements in a simulation across all processors. - * \returns Total number of prism elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemPris(); - - /*! - * \brief Retrieve total number of pyramid elements in a simulation across all processors. - * \returns Total number of pyramid elements in a simulation across all processors. - */ - unsigned long GetGlobal_nElemPyra(); - - /*! - * \brief Get number of triangular elements. - * \return Number of line elements. - */ - unsigned long GetnElemLine(); - - /*! - * \brief Get number of triangular elements. - * \return Number of triangular elements. - */ - unsigned long GetnElemTria(); - - /*! - * \brief Get number of quadrilateral elements. - * \return Number of quadrilateral elements. - */ - unsigned long GetnElemQuad(); - - /*! - * \brief Get number of tetrahedral elements. - * \return Number of tetrahedral elements. - */ - unsigned long GetnElemTetr(); - - /*! - * \brief Get number of hexahedral elements. - * \return Number of hexahedral elements. - */ - unsigned long GetnElemHexa(); - - /*! - * \brief Get number of prism elements. - * \return Number of prism elements. - */ - unsigned long GetnElemPris(); - - /*! - * \brief Get number of pyramid elements. - * \return Number of pyramid elements. - */ - unsigned long GetnElemPyra(); - - /*! - * \brief Indentify geometrical planes in the mesh - */ - void SetGeometryPlanes(CConfig *config); - - /*! - * \brief Get geometrical planes in the mesh - */ - vector GetGeometryPlanes(); - - /*! - * \brief Get x coords of geometrical planes in the mesh - */ - vector > GetXCoord(); - - /*! - * \brief Get y coords of geometrical planes in the mesh - */ - vector > GetYCoord(); - - /*! - * \brief Get z coords of geometrical planes in the mesh - */ - vector > GetZCoord(); - - /*! - * \brief Get all points on a geometrical plane in the mesh - */ - vector > GetPlanarPoints(); - - /*! - * \brief Read the sensitivity from an input file. - * \param[in] config - Definition of the particular problem. - */ - void SetBoundSensitivity(CConfig *config); - - /*! - * \brief Compute the maximum thickness of an airfoil. - * \returns Maximum thickness at a particular seccion. - */ - su2double Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the twist of an airfoil. - * \returns Twist at a particular seccion. - */ - su2double Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the leading/trailing edge location of an airfoil. - */ - void Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, - vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the leading/trailing edge location of a fuselage. - */ - void Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, - vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the chord of an airfoil. - * \returns Chord of an airfoil. - */ - su2double Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the chord of an airfoil. - * \returns Chord of an airfoil. - */ - su2double Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the chord of an airfoil. - * \returns Chord of an airfoil. - */ - su2double Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the chord of an airfoil. - * \returns Chord of an airfoil. - */ - su2double Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the chord of an airfoil. - * \returns Chord of an airfoil. - */ - su2double Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the thickness of an airfoil. - */ - su2double Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, su2double &ZLoc); - - /*! - * \brief Compute the area of an airfoil. - * \returns Area of an airfoil. - */ - su2double Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the length of an airfoil. - * \returns Area of an airfoil. - */ - su2double Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil); - - /*! - * \brief Compute the dihedral of a wing. - * \returns Dihedral at a particular seccion. - */ - su2double Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, - su2double *LeadingEdge_i, su2double *TrailingEdge_i); - - /*! - * \brief Compute the curvature of a wing. - */ - su2double Compute_Curvature(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, - su2double *LeadingEdge_i, su2double *TrailingEdge_i, - su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1); - - /*! - * \brief Evaluate geometrical parameters of a wing. - */ - void Compute_Wing(CConfig *config, bool original_surface, - su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, - su2double &Wing_MinChord, su2double &Wing_MaxChord, - su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius, - su2double &Wing_MinToC, su2double &Wing_MaxToC, - su2double &Wing_ObjFun_MinToC, su2double &Wing_MaxTwist, - su2double &Wing_MaxCurvature, su2double &Wing_MaxDihedral); - - /*! - * \brief Evaluate geometrical parameters of a wing. - */ - void Compute_Fuselage(CConfig *config, bool original_surface, - su2double &Fuselage_Volume, su2double &Fuselage_WettedArea, - su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth, - su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth, - su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight, - su2double &Fuselage_MaxCurvature); - - /*! - * \brief Evaluate geometrical parameters of a wing. - */ - void Compute_Nacelle(CConfig *config, bool original_surface, - su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness, su2double &Nacelle_MaxMaxThickness, - su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord, - su2double &Nacelle_MinLERadius, su2double &Nacelle_MaxLERadius, - su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC, - su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist); - - /*! - * \brief Read the sensitivity from adjoint solution file and store it. - * \param[in] config - Definition of the particular problem. - */ - void SetSensitivity(CConfig *config); - - /*! - * \brief Read the sensitivity from unordered ASCII adjoint solution file and store it. - * \param[in] config - Definition of the particular problem. - */ - void ReadUnorderedSensitivity(CConfig *config); - - /*! - * \brief Get the Sensitivity at a specific point. - * \param[in] iPoint - The point where to get the sensitivity. - * \param[in] iDim - The component of the dim. vector. - * \returns The sensitivity at point iPoint and dim. iDim. - */ - su2double GetSensitivity(unsigned long iPoint, unsigned short iDim); - - /*! - * \brief Set the Sensitivity at a specific point. - * \param[in] iPoint - The point where to get the sensitivity. - * \param[in] iDim - The component of the dim. vector. - * \param[in] val - Value of the sensitivity. - */ - void SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val); - - /*! - * \brief Check the mesh for periodicity and deactivate multigrid if periodicity is found. - * \param[in] config - Definition of the particular problem. - */ - void Check_Periodicity(CConfig *config); - - /*! - * \brief Get the average normal at a specific span for a given marker in the turbomachinery reference of frame. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - * \return The span-wise averaged turbo normal. - */ - su2double* GetAverageTurboNormal(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the average normal at a specific span for a given marker. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - * \return The span-wise averaged normal. - */ - su2double* GetAverageNormal(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the total area for each span. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - * \return The span-wise area. - */ - su2double GetSpanArea(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the total area for each span. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - * \return The span-wise averaged turbo normal. - */ - su2double GetTurboRadius(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the average tangential rotational velocity for each span. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - * \return The span-wise averaged tangential velocity. - */ - su2double GetAverageTangGridVel(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the inflow tangential velocity at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise inflow tangential velocity. - */ - su2double GetTangGridVelIn(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the outflow tangential velocity at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise outflow tangential velocity. - */ - su2double GetTangGridVelOut(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the inflow area at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise inflow area. - */ - su2double GetSpanAreaIn(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the outflow area at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise outflow area. - */ - su2double GetSpanAreaOut(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the inflow radius at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise inflow radius. - */ - su2double GetTurboRadiusIn(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the outflow radius at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - * \return The span-wise outflow radius. - */ - su2double GetTurboRadiusOut(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Set the value of the inflow tangential velocity at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - void SetTangGridVelIn(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Set the value of the outflow tangential velocity at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - void SetTangGridVelOut(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the value of the inflow area at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - void SetSpanAreaIn(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Set the value of the outflow area at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - void SetSpanAreaOut(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Set the value of the inflow radius at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - void SetTurboRadiusIn(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Set the value of the outflow radius at each span. - * \param[in] val_marker - marker turbo-performance value. - * \param[in] val_span - span value. - */ - void SetTurboRadiusOut(su2double value, unsigned short val_marker, unsigned short val_span); - - /*! - * \brief A total number of vertex independently from the MPI partions. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - unsigned long GetnTotVertexSpan(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief min angular pitch independently from the MPI partions. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - su2double GetMinAngularCoord(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief max angular pitch independently from the MPI partions. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - su2double GetMaxAngularCoord(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief min Relatice angular coord independently from the MPI partions. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - su2double GetMinRelAngularCoord(unsigned short val_marker, unsigned short val_span); - - /*! - * \brief Get the average grid velocity at a specific span for a given marker. - * \param[in] val_marker - marker value. - * \param[in] val_span - span value. - */ - su2double* GetAverageGridVel(unsigned short val_marker, unsigned short val_span); - -}; - -/*! - * \class CMultiGridGeometry - * \brief Class for defining the multigrid geometry, the main delicated part is the - * agglomeration stage, which is done in the declaration. - * \author F. Palacios - */ -class CMultiGridGeometry : public CGeometry { - -public: - - /*! - * \brief Constructor of the class. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] iMesh - Level of the multigrid. - * \param[in] iZone - Current zone in the mesh. - */ - CMultiGridGeometry(CGeometry **geometry, CConfig *config_container, unsigned short iMesh); - - /*! - * \brief Destructor of the class. - */ - ~CMultiGridGeometry(void); - - /*! - * \brief Determine if a CVPoint van be agglomerated, if it have the same marker point as the seed. - * \param[in] CVPoint - Control volume to be agglomerated. - * \param[in] marker_seed - Marker of the seed. - * \param[in] fine_grid - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \return TRUE or FALSE depending if the control volume can be agglomerated. - */ - bool SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config); - - /*! - * \brief Determine if a can be agglomerated using geometrical criteria. - * \param[in] iPoint - Seed point. - * \param[in] fine_grid - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - bool GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config); - - /*! - * \brief Determine if a CVPoint van be agglomerated, if it have the same marker point as the seed. - * \param[in] Suitable_Indirect_Neighbors - List of Indirect Neighbours that can be agglomerated. - * \param[in] iPoint - Seed point. - * \param[in] Index_CoarseCV - Index of agglomerated point. - * \param[in] fine_grid - Geometrical definition of the problem. - */ - void SetSuitableNeighbors(vector *Suitable_Indirect_Neighbors, unsigned long iPoint, - unsigned long Index_CoarseCV, CGeometry *fine_grid); - - /*! - * \brief Set boundary vertex. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetVertex(CGeometry *geometry, CConfig *config); - - /*! - * \brief Set points which surround a point. - * \param[in] geometry - Geometrical definition of the problem. - */ - void SetPoint_Connectivity(CGeometry *geometry); - - /*! - * \brief Function declaration to avoid partially overridden classes. - */ - void SetPoint_Connectivity(void); - - /*! - * \brief Set the edge structure of the agglomerated control volume. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] action - Allocate or not the new elements. - */ - void SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action); - - /*! - * \brief Mach the near field boundary condition. - * \param[in] config - Definition of the particular problem. - */ - void MatchNearField(CConfig *config); - - /*! - * \brief Mach the near field boundary condition. - * \param[in] config - Definition of the particular problem. - */ - void MatchActuator_Disk(CConfig *config); - - /*! - * \brief Mach the periodic boundary conditions. - * \param[in] config - Definition of the particular problem. - * \param[in] val_periodic - Index of the first periodic face in a pair. - */ - void MatchPeriodic(CConfig *config, unsigned short val_periodic); - - /*! - * \brief Set boundary vertex structure of the agglomerated control volume. - * \param[in] config - Definition of the particular problem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] action - Allocate or not the new elements. - */ - void SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action); - - /*! - * \brief Set a representative coordinates of the agglomerated control volume. - * \param[in] geometry - Geometrical definition of the problem. - */ - void SetCoord(CGeometry *geometry); - - /*! - * \brief Set a representative wall normal heat flux of the agglomerated control volume on a particular boundary marker. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_marker - Index of the boundary marker. - */ - void SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker); - - /*! - * \brief Set a representative wall temperature of the agglomerated control volume on a particular boundary marker. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] val_marker - Index of the boundary marker. - */ - void SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker); - - /*! - * \brief Set the rotational velocity at each grid point on a coarse mesh. - * \param[in] config - Definition of the particular problem. - * \param[in] val_iZone - Index of the current zone. - */ - void SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print); - - /*! - * \brief Set the rotational velocity of the points on the shroud markers to 0.0. - * \param[in] config - Definition of the particular problem. - */ - void SetShroudVelocity(CConfig *config); - - /*! - * \brief Set the translational velocity at each grid point on a coarse mesh. - * \param[in] config - Definition of the particular problem. - */ - void SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print); - - /*! - * \brief Set the grid velocity at each node in the coarse mesh level. - * \param[in] config - Definition of the particular problem. - * \param[in] iter - Current physical time step. - */ - void SetGridVelocity(CConfig *config, unsigned long iter); - - /*! - * \brief Set the grid velocity at each node in the coarse mesh level based - * on a restriction from a finer mesh. - * \param[in] fine_mesh - Geometry container for the finer mesh level. - * \param[in] config - Definition of the particular problem. - */ - void SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config); - - /*! - * \brief Find and store the closest neighbor to a vertex. - * \param[in] config - Definition of the particular problem. - */ - void FindNormal_Neighbor(CConfig *config); - - /*! - * \brief Indentify geometrical planes in the mesh - */ - void SetGeometryPlanes(CConfig *config); - - /*! - * \brief Get geometrical planes in the mesh - */ - vector GetGeometryPlanes(); - - /*! - * \brief Get x coords of geometrical planes in the mesh - */ - vector > GetXCoord(); - - /*! - * \brief Get y coords of geometrical planes in the mesh - */ - vector > GetYCoord(); - - /*! - * \brief Get z coords of geometrical planes in the mesh - */ - vector > GetZCoord(); - - /*! - * \brief Get all points on a geometrical plane in the mesh - */ - vector > GetPlanarPoints(); - -}; - -/*! - * \class CDummyGeometry - * \brief Class for defining a geometry that does not contain any points/elements. - * Can be used for initializing other classes that depend on the geometry without - * going through the time-consuming mesh initialization and paritioning. - * \author T. Albring - */ -class CDummyGeometry : public CGeometry{ - -public: - /*! - * \brief Constructor of the class - * \param[in] config - Definition of the particular problem. - */ - CDummyGeometry(CConfig *config); - - /*! - * \brief Destructor of the class. - */ - ~CDummyGeometry(); - -}; - -#include "geometry_structure.inl" diff --git a/Common/include/geometry_structure.inl b/Common/include/geometry_structure.inl deleted file mode 100644 index a608fb0d55b4..000000000000 --- a/Common/include/geometry_structure.inl +++ /dev/null @@ -1,521 +0,0 @@ -/*! - * \file geometry_structure.inl - * \brief In-Line subroutines of the geometry_structure.hpp file. - * \author F. Palacios, T. Economon - * \version 7.0.0 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2019, 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 - -inline CUnsignedLong2T::CUnsignedLong2T(){long0 = long1 = 0;} - -inline CUnsignedLong2T::CUnsignedLong2T(const unsigned long a, const unsigned long b){long0 = a; long1 = b;} - -inline CUnsignedLong2T::~CUnsignedLong2T(){} - -inline CUnsignedLong2T::CUnsignedLong2T(const CUnsignedLong2T &other){Copy(other);} - -inline CUnsignedLong2T& CUnsignedLong2T::operator=(const CUnsignedLong2T &other){Copy(other); return (*this);} - -inline CUnsignedShort2T::CUnsignedShort2T(){short0 = short1 = 0;} - -inline CUnsignedShort2T::CUnsignedShort2T(const unsigned short a, const unsigned short b){short0 = a; short1 = b;} - -inline CUnsignedShort2T::~CUnsignedShort2T(){} - -inline CUnsignedShort2T::CUnsignedShort2T(const CUnsignedShort2T &other){Copy(other);} - -inline CUnsignedShort2T& CUnsignedShort2T::operator=(const CUnsignedShort2T &other){Copy(other); return (*this);} - -inline CFaceOfElement::CFaceOfElement(const CFaceOfElement &other){Copy(other);} - -inline CFaceOfElement& CFaceOfElement::operator=(const CFaceOfElement &other){Copy(other); return (*this);} - -inline void CFaceOfElement::CreateUniqueNumbering(void){sort(cornerPoints, cornerPoints+nCornerPoints);} - -inline CBoundaryFace::CBoundaryFace(const CBoundaryFace &other){Copy(other);} - -inline CBoundaryFace& CBoundaryFace::operator=(const CBoundaryFace &other){Copy(other); return (*this);} - -inline bool CBoundaryFace::operator<(const CBoundaryFace &other) const {return (globalBoundElemID < other.globalBoundElemID);} - -inline CMatchingFace::CMatchingFace(const CMatchingFace &other){Copy(other);} - -inline CMatchingFace& CMatchingFace::operator=(const CMatchingFace &other){Copy(other); return (*this);} - -inline void CGeometry::SetGlobal_to_Local_Point(void) { } - -inline long CGeometry::GetGlobal_to_Local_Point(unsigned long val_ipoint) { return 0; } - -inline unsigned short CGeometry::GetGlobal_to_Local_Marker(unsigned short val_imarker) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nPoint(void) { return 0; } - -inline void CGeometry::SetGlobal_nPointDomain(unsigned long val_global_npoint) { } - -inline unsigned long CGeometry::GetGlobal_nPointDomain(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElem(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemDomain(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemLine(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemTria(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemQuad(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemTetr(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemHexa(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemPris(void) { return 0; } - -inline unsigned long CGeometry::GetGlobal_nElemPyra(void) { return 0; } - -inline unsigned long CGeometry::GetnElemLine(void) { return 0; } - -inline unsigned long CGeometry::GetnElemTria(void) { return 0; } - -inline unsigned long CGeometry::GetnElemQuad(void) { return 0; } - -inline unsigned long CGeometry::GetnElemTetr(void) { return 0; } - -inline unsigned long CGeometry::GetnElemHexa(void) { return 0; } - -inline unsigned long CGeometry::GetnElemPris(void) { return 0; } - -inline unsigned long CGeometry::GetnElemPyra(void) { return 0; } - -inline void CGeometry::Check_IntElem_Orientation(CConfig *config) { } - -inline void CGeometry::Check_BoundElem_Orientation(CConfig *config) { } - -inline void CGeometry::SetColorGrid(CConfig *config) { } - -inline void CGeometry::SetColorGrid_Parallel(CConfig *config) { } - -inline void CGeometry::SetColorFEMGrid_Parallel(CConfig *config) { } - -inline void CGeometry::DivideConnectivity(CConfig *config, unsigned short Elem_Type) { } - -inline void CGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print) { } - -inline void CGeometry::SetShroudVelocity(CConfig *config){ } - -inline void CGeometry::SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print) { } - -inline void CGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { } - -inline void CGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { } - -inline void CGeometry::SetSendReceive(CConfig *config) { } - -inline void CGeometry::SetBoundaries(CConfig *config) { } - -inline void CGeometry::ComputeWall_Distance(CConfig *config) { } - -inline void CGeometry::SetPositive_ZArea(CConfig *config) { } - -inline void CGeometry::SetPoint_Connectivity(void) { } - -inline void CGeometry::SetRCM_Ordering(CConfig *config) { } - -inline void CGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2double val_smooth_coeff, CConfig *config) { } - -inline void CGeometry::SetCoord(CGeometry *geometry) { } - -inline void CGeometry::SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker){ } - -inline void CGeometry::SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker){ } - -inline void CGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { } - -inline void CGeometry::SetElement_Connectivity(void) { } - -inline unsigned long CGeometry::GetnPoint(void) { return nPoint; } - -inline unsigned long CGeometry::GetnPointDomain(void) { return nPointDomain; } - -inline unsigned long CGeometry::GetnElem(void) { return nElem; } - -inline unsigned short CGeometry::GetnDim(void) { return nDim; } - -inline unsigned short CGeometry::GetnZone(void) { return nZone; } - -inline unsigned short CGeometry::GetnMarker(void) { return nMarker; } - -inline string CGeometry::GetMarker_Tag(unsigned short val_marker) { return Tag_to_Marker[val_marker]; } - -inline unsigned long CGeometry::GetMax_GlobalPoint(void) { return Max_GlobalPoint; } - -inline void CGeometry::SetnMarker(unsigned short val_nmarker) { nMarker = val_nmarker; } - -inline void CGeometry::SetnElem_Bound(unsigned short val_marker, unsigned long val_nelem_bound) { nElem_Bound[val_marker]= val_nelem_bound; } - -inline unsigned long CGeometry::GetnElem_Bound(unsigned short val_marker) { return nElem_Bound[val_marker]; } - -inline void CGeometry::SetMarker_Tag(unsigned short val_marker, string val_index) { Tag_to_Marker[val_marker] = val_index; } - -inline void CGeometry::SetnPoint(unsigned long val_npoint) { nPoint = val_npoint; } - -inline void CGeometry::SetnPointDomain(unsigned long val_npoint) { nPointDomain = val_npoint; } - -inline void CGeometry::SetnElem(unsigned long val_nelem) { nElem = val_nelem; } - -inline void CGeometry::SetnDim(unsigned short val_nDim) { nDim = val_nDim; } - -inline su2double* CGeometry::GetSpanWiseValue(unsigned short val_marker) { return SpanWiseValue[val_marker-1]; } - -inline unsigned long CGeometry::GetnVertex(unsigned short val_marker) { return nVertex[val_marker]; } - -inline unsigned short CGeometry::GetnSpanWiseSections(unsigned short marker_flag) { return nSpanWiseSections[marker_flag -1]; } - -inline unsigned long CGeometry::GetnVertexSpan(unsigned short val_marker, unsigned short val_span) { return nVertexSpan[val_marker][val_span]; } - -inline unsigned long CGeometry::GetnFreqSpan(unsigned short val_marker, unsigned short val_span) { return (nTotVertexSpan[val_marker][val_span]/2 -1); } - -inline unsigned long CGeometry::GetnVertexSpanMax(unsigned short marker_flag){return nVertexSpanMax[marker_flag];} - -inline unsigned long CGeometry::GetnFreqSpanMax(unsigned short marker_flag){return (nVertexSpanMax[marker_flag]/2 -1);} - -inline void CGeometry::SetnVertexSpanMax(unsigned short marker_flag, unsigned long nVertMax){nVertexSpanMax[marker_flag] = nVertMax;} - -inline unsigned long CGeometry::GetnEdge(void) { return nEdge; } - -inline bool CGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, unsigned short &face_second_elem) { return 0;} - -inline void CGeometry::SetBoundVolume(void) { } - -inline void CGeometry::SetVertex(void) { } - -inline void CGeometry::SetVertex(CConfig *config) { } - -inline void CGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, unsigned short marker_flag, bool allocate) { } - -inline void CGeometry::SetTurboVertex(CConfig *config,unsigned short val_iZone, unsigned short marker_flag, bool allocate) { } - -inline void CGeometry::UpdateTurboVertex(CConfig *config,unsigned short val_iZone, unsigned short marker_flag) { } - -inline void CGeometry::SetAvgTurboValue(CConfig *config,unsigned short val_iZone, unsigned short marker_flag, bool allocate) { } - -inline void CGeometry::GatherInOutAverageValues(CConfig *config, bool allocate){ } - -inline su2double* CGeometry::GetAverageTurboNormal(unsigned short val_marker, unsigned short val_span){ return NULL;} - -inline su2double* CGeometry::GetAverageGridVel(unsigned short val_marker, unsigned short val_span){ return NULL;} - -inline su2double CGeometry::GetAverageTangGridVel(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double* CGeometry::GetAverageNormal(unsigned short val_marker, unsigned short val_span){return NULL;} - -inline su2double CGeometry::GetSpanArea(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetTurboRadius(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetTangGridVelIn(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetTangGridVelOut(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetSpanAreaIn(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetSpanAreaOut(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetTurboRadiusIn(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetTurboRadiusOut(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline void CGeometry::SetTangGridVelIn(su2double value, unsigned short val_marker, unsigned short val_span){ } - -inline void CGeometry::SetTangGridVelOut(su2double value, unsigned short val_marker, unsigned short val_span){ } - -inline void CGeometry::SetSpanAreaIn(su2double value, unsigned short val_marker, unsigned short val_span){ } - -inline void CGeometry::SetSpanAreaOut(su2double value, unsigned short val_marker, unsigned short val_span){ } - -inline void CGeometry::SetTurboRadiusIn(su2double value, unsigned short val_marker, unsigned short val_span){ } - -inline void CGeometry::SetTurboRadiusOut(su2double value, unsigned short val_marker, unsigned short val_span){ } - -inline unsigned long CGeometry::GetnTotVertexSpan(unsigned short val_marker, unsigned short val_span){return 0;} - -inline su2double CGeometry::GetMinAngularCoord(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetMaxAngularCoord(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline su2double CGeometry::GetMinRelAngularCoord(unsigned short val_marker, unsigned short val_span){return 0.0;} - -inline void CGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { } - -inline void CGeometry::SetCoord_CG(void) { } - -inline void CGeometry::SetMaxLength(CConfig* config) { } - -inline void CGeometry::SetControlVolume(CConfig *config, unsigned short action) { } - -inline void CGeometry::SetControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) { } - -inline void CGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) { } - -inline void CGeometry::MatchNearField(CConfig *config) { } - -inline void CGeometry::MatchActuator_Disk(CConfig *config) { } - -inline void CGeometry::MatchPeriodic(CConfig *config, unsigned short val_periodic) { } - -inline void CGeometry::SetBoundControlVolume(CConfig *config, unsigned short action) { } - -inline void CGeometry::SetBoundControlVolume(CConfig *config, CGeometry *geometry, unsigned short action) { } - -inline void CGeometry::SetTecPlot(char config_filename[MAX_STRING_SIZE], bool new_file) { } - -inline void CGeometry::SetMeshFile(CConfig *config, string val_mesh_out_filename) { } - -inline void CGeometry::SetMeshFile(CGeometry *geometry, CConfig *config, string val_mesh_out_filename) { } - -inline void CGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { } - -inline su2double CGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, su2double &ZLoc) { return 0; } - -inline su2double CGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline su2double CGeometry::Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { return 0; } - -inline void CGeometry::Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, - vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, - vector &Zcoord_Airfoil) { } - -inline void CGeometry::Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, - vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, - vector &Zcoord_Airfoil) { } - -inline su2double CGeometry::Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, - su2double *LeadingEdge_i, su2double *TrailingEdge_i) { return 0; } - -inline su2double CGeometry::Compute_Curvature(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, - su2double *LeadingEdge_i, su2double *TrailingEdge_i, - su2double *LeadingEdge_ip1, su2double *TrailingEdge_ip1) { return 0; } - -inline void CGeometry::Compute_Wing(CConfig *config, bool original_surface, - su2double &Wing_Volume, su2double &Wing_MinMaxThickness, su2double &Wing_MaxMaxThickness, - su2double &Wing_MinChord, su2double &Wing_MaxChord, - su2double &Wing_MinLERadius, su2double &Wing_MaxLERadius, - su2double &Wing_MinToC, su2double &Wing_MaxToC, su2double &Wing_ObjFun_MinToC, - su2double &Wing_MaxTwist, su2double &Wing_MaxCurvature, - su2double &Wing_MaxDihedral) { } - - -inline void CGeometry::Compute_Fuselage(CConfig *config, bool original_surface, - su2double &Fuselage_Volume, su2double &Fuselage_WettedArea, - su2double &Fuselage_MinWidth, su2double &Fuselage_MaxWidth, - su2double &Fuselage_MinWaterLineWidth, su2double &Fuselage_MaxWaterLineWidth, - su2double &Fuselage_MinHeight, su2double &Fuselage_MaxHeight, - su2double &Fuselage_MaxCurvature) { } - -inline void CGeometry::Compute_Nacelle(CConfig *config, bool original_surface, - su2double &Nacelle_Volume, su2double &Nacelle_MinMaxThickness, su2double &Nacelle_MaxMaxThickness, - su2double &Nacelle_MinChord, su2double &Nacelle_MaxChord, - su2double &Nacelle_MinLERadius, su2double &Nacelle_MaxLERadius, - su2double &Nacelle_MinToC, su2double &Nacelle_MaxToC, - su2double &Nacelle_ObjFun_MinToC, su2double &Nacelle_MaxTwist) { } - -inline void CGeometry::FindNormal_Neighbor(CConfig *config) { } - -inline void CGeometry::SetBoundSensitivity(CConfig *config) { } - -inline su2double CGeometry::GetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex){ return CustomBoundaryTemperature[val_marker][val_vertex]; } - -inline void CGeometry::SetCustomBoundaryTemperature(unsigned short val_marker, unsigned long val_vertex, su2double val_customBoundaryTemperature){ CustomBoundaryTemperature[val_marker][val_vertex] = val_customBoundaryTemperature; } - -inline su2double CGeometry::GetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex){ return CustomBoundaryHeatFlux[val_marker][val_vertex]; } - -inline void CGeometry::SetCustomBoundaryHeatFlux(unsigned short val_marker, unsigned long val_vertex, su2double val_customBoundaryHeatFlux){ CustomBoundaryHeatFlux[val_marker][val_vertex] = val_customBoundaryHeatFlux; } - -inline void CGeometry::SetMGLevel(unsigned short val_iMesh) { MGLevel = val_iMesh; } - -inline unsigned short CGeometry::GetMGLevel(void) { return MGLevel; } - -inline void CPhysicalGeometry::SetPoint_Connectivity(CGeometry *geometry) { CGeometry::SetPoint_Connectivity(geometry); } - -inline void CMultiGridGeometry::SetPoint_Connectivity(void) { CGeometry::SetPoint_Connectivity(); } - -inline void CPhysicalGeometry::SetGlobal_to_Local_Point(void) { - Global_to_Local_Point.clear(); - for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { - Global_to_Local_Point[node[iPoint]->GetGlobalIndex()] = iPoint; - } -} - -inline long CPhysicalGeometry::GetGlobal_to_Local_Point(unsigned long val_ipoint) { - map::const_iterator MI = Global_to_Local_Point.find(val_ipoint); - if (MI != Global_to_Local_Point.end()) { - return Global_to_Local_Point[val_ipoint]; - } else { - return -1; - } -} - -inline unsigned short CPhysicalGeometry::GetGlobal_to_Local_Marker(unsigned short val_imarker) { return Global_to_Local_Marker[val_imarker]; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nPoint(void) { return Global_nPoint; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nPointDomain(void) { return Global_nPointDomain; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElem(void) { return Global_nElem; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemDomain(void) { return Global_nElemDomain; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemLine(void) { return Global_nelem_edge; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemTria(void) { return Global_nelem_triangle; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemQuad(void) { return Global_nelem_quad; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemTetr(void) { return Global_nelem_tetra; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemHexa(void) { return Global_nelem_hexa; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemPris(void) { return Global_nelem_prism; } - -inline unsigned long CPhysicalGeometry::GetGlobal_nElemPyra(void) { return Global_nelem_pyramid; } - -inline unsigned long CPhysicalGeometry::GetnElemLine(void) { return nelem_edge; } - -inline unsigned long CPhysicalGeometry::GetnElemTria(void) { return nelem_triangle; } - -inline unsigned long CPhysicalGeometry::GetnElemQuad(void) { return nelem_quad; } - -inline unsigned long CPhysicalGeometry::GetnElemTetr(void) { return nelem_tetra; } - -inline unsigned long CPhysicalGeometry::GetnElemHexa(void) { return nelem_hexa; } - -inline unsigned long CPhysicalGeometry::GetnElemPris(void) { return nelem_prism; } - -inline unsigned long CPhysicalGeometry::GetnElemPyra(void) { return nelem_pyramid; } - -inline void CGeometry::SetGeometryPlanes(CConfig *config) {} - -inline vector CGeometry::GetGeometryPlanes() { return XCoordList; } - -inline vector CPhysicalGeometry::GetGeometryPlanes() { return XCoordList; } - -inline vector CMultiGridGeometry::GetGeometryPlanes() { return XCoordList; } - -inline vector > CGeometry::GetXCoord() { return Xcoord_plane; } - -inline vector > CPhysicalGeometry::GetXCoord() { return Xcoord_plane; } - -inline vector > CMultiGridGeometry::GetXCoord() { return Xcoord_plane; } - -inline vector > CGeometry::GetYCoord() { return Ycoord_plane; } - -inline vector > CPhysicalGeometry::GetYCoord() { return Ycoord_plane; } - -inline vector > CMultiGridGeometry::GetYCoord() { return Ycoord_plane; } - -inline vector > CGeometry::GetZCoord() { return Zcoord_plane; } - -inline vector > CPhysicalGeometry::GetZCoord() { return Zcoord_plane; } - -inline vector > CMultiGridGeometry::GetZCoord() { return Zcoord_plane; } - - -inline vector > CGeometry::GetPlanarPoints() { return Plane_points; } - -inline vector > CPhysicalGeometry::GetPlanarPoints() { return Plane_points; } - -inline vector > CMultiGridGeometry::GetPlanarPoints() { return Plane_points; } - -inline void CGeometry::SetSensitivity(CConfig* config) {} - -inline void CGeometry::ReadUnorderedSensitivity(CConfig* config) {} - -inline su2double CGeometry::GetSensitivity(unsigned long iPoint, unsigned short iDim) { return 0.0;} - -inline void CGeometry::ComputeMeshQualityStatistics(CConfig* config) {} - -inline su2double CPhysicalGeometry::GetSensitivity(unsigned long iPoint, unsigned short iDim) { return Sensitivity[iPoint*nDim+iDim];} - -inline void CGeometry::SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val) {} - -inline void CPhysicalGeometry::SetSensitivity(unsigned long iPoint, unsigned short iDim, su2double val) {Sensitivity[iPoint*nDim+iDim] = val;} - -inline su2double* CPhysicalGeometry::GetAverageTurboNormal(unsigned short val_marker, unsigned short val_span){return AverageTurboNormal[val_marker][val_span];} - -inline su2double* CPhysicalGeometry::GetAverageGridVel(unsigned short val_marker, unsigned short val_span){return AverageGridVel[val_marker][val_span]; } - -inline su2double CPhysicalGeometry::GetAverageTangGridVel(unsigned short val_marker, unsigned short val_span){return AverageTangGridVel[val_marker][val_span]; } - -inline su2double* CPhysicalGeometry::GetAverageNormal(unsigned short val_marker, unsigned short val_span){return AverageNormal[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetSpanArea(unsigned short val_marker, unsigned short val_span){return SpanArea[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetTurboRadius(unsigned short val_marker, unsigned short val_span){return TurboRadius[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetTangGridVelIn(unsigned short val_marker, unsigned short val_span){return TangGridVelIn[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetTangGridVelOut(unsigned short val_marker, unsigned short val_span){return TangGridVelOut[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetSpanAreaIn(unsigned short val_marker, unsigned short val_span){return SpanAreaIn[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetSpanAreaOut(unsigned short val_marker, unsigned short val_span){return SpanAreaOut[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetTurboRadiusIn(unsigned short val_marker, unsigned short val_span){return TurboRadiusIn[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetTurboRadiusOut(unsigned short val_marker, unsigned short val_span){return TurboRadiusOut[val_marker][val_span];} - -inline void CPhysicalGeometry::SetTangGridVelIn(su2double value, unsigned short val_marker, unsigned short val_span){TangGridVelIn[val_marker][val_span] = value;} - -inline void CPhysicalGeometry::SetTangGridVelOut(su2double value, unsigned short val_marker, unsigned short val_span){TangGridVelOut[val_marker][val_span] = value;} - -inline void CPhysicalGeometry::SetSpanAreaIn(su2double value, unsigned short val_marker, unsigned short val_span){SpanAreaIn[val_marker][val_span] = value;} - -inline void CPhysicalGeometry::SetSpanAreaOut(su2double value, unsigned short val_marker, unsigned short val_span){SpanAreaOut[val_marker][val_span] = value;} - -inline void CPhysicalGeometry::SetTurboRadiusIn(su2double value, unsigned short val_marker, unsigned short val_span){ TurboRadiusIn[val_marker][val_span] = value;} - -inline void CPhysicalGeometry::SetTurboRadiusOut(su2double value, unsigned short val_marker, unsigned short val_span){TurboRadiusOut[val_marker][val_span] = value;} - -inline unsigned long CPhysicalGeometry::GetnTotVertexSpan(unsigned short val_marker, unsigned short val_span){return nTotVertexSpan[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetMinAngularCoord(unsigned short val_marker, unsigned short val_span){return MinAngularCoord[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetMaxAngularCoord(unsigned short val_marker, unsigned short val_span){return MaxAngularCoord[val_marker][val_span];} - -inline su2double CPhysicalGeometry::GetMinRelAngularCoord(unsigned short val_marker, unsigned short val_span){return MinRelAngularCoord[val_marker][val_span];} - -inline void CGeometry::Check_Periodicity(CConfig* config) {} diff --git a/Common/include/geometry_structure_fem_part.hpp b/Common/include/geometry_structure_fem_part.hpp new file mode 100644 index 000000000000..1fc5d70fd8b6 --- /dev/null +++ b/Common/include/geometry_structure_fem_part.hpp @@ -0,0 +1,210 @@ +/*! + * \file geometry_structure_fem_part.hpp + * \brief Helper classes for the Fluid FEM solver. + * \author E. van der Weide + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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 "datatype_structure.hpp" + +#include +#include + +/*! + * \struct CUnsignedLong2T + * \brief Helper struct used to store two integral types as one entity. + */ +struct CUnsignedLong2T { + + unsigned long long0; /*!< \brief First integer to store in this class. */ + unsigned long long1; /*!< \brief Second integer to store in this class. */ + + CUnsignedLong2T(unsigned long a = 0, unsigned long b = 0) : long0(a), long1(b) {} + + inline bool operator<(const CUnsignedLong2T &other) const { + if(long0 != other.long0) + return (long0 < other.long0); + return (long1 < other.long1); + } + + inline bool operator==(const CUnsignedLong2T &other) const { + return (long0 == other.long0) && (long1 == other.long1); + } +}; + +/*! + * \struct CUnsignedShort2T + * \brief Help struct used to store two integral types as one entity. + */ +struct CUnsignedShort2T { + + unsigned short short0; /*!< \brief First integer to store in this class. */ + unsigned short short1; /*!< \brief Second integer to store in this class. */ + + CUnsignedShort2T(unsigned short a = 0, unsigned short b = 0) : short0(a), short1(b) {} + + inline bool operator<(const CUnsignedShort2T &other) const { + if(short0 != other.short0) + return (short0 < other.short0); + return (short1 < other.short1); + } + + inline bool operator==(const CUnsignedShort2T &other) const { + return (short0 == other.short0) && (short1 == other.short1); + } +}; + +/*! + * \class CFaceOfElement + * \brief Class used in the partitioning of the FEM grid as well as the building of + the faces of DG. It stores a face of an element. + */ +class CFaceOfElement { +public: + unsigned short nCornerPoints; /*!< \brief Number of corner points of the face. */ + unsigned long cornerPoints[4]; /*!< \brief Global ID's of ther corner points. */ + unsigned long elemID0, elemID1; /*!< \brief Element ID's to the left and right. */ + unsigned short nPolyGrid0, nPolyGrid1; /*!< \brief Polynomial degrees of the grid of the elements + to the left and right. */ + unsigned short nPolySol0, nPolySol1; /*!< \brief Polynomial degrees of the solution of the elements + to the left and right. */ + unsigned short nDOFsElem0, nDOFsElem1; /*!< \brief Number of DOFs of the elements to the left and right. */ + unsigned short elemType0, elemType1; /*!< \brief Type of the elements to the left and right. */ + unsigned short faceID0, faceID1; /*!< \brief The local face ID in the corresponding elements + to the left and right of the face. */ + unsigned short periodicIndex; /*!< \brief Periodic indicator of the face. A value of 0 means no + periodic face. A value larger than 0 gives the index of + the periodic boundary + 1. */ + unsigned short periodicIndexDonor; /*!< \brief Periodic indicator of the donor face. A value of 0 means no + periodic donor face. A value larger than 0 gives the index of + the periodic donor boundary + 1. */ + short faceIndicator; /*!< \brief The corresponding boundary marker if this face is on a + boundary. For an internal face the value is -1, + while an invalidated face has the value -2. */ + bool JacFaceIsConsideredConstant; /*!< \brief Whether or not the Jacobian of the transformation + to the standard element is considered constant. */ + bool elem0IsOwner; /*!< \brief Whether or not the neighboring element 0 is the owner + of the face. If false, element 1 is the owner. */ + + /* Standard constructor and destructor. */ + CFaceOfElement(); + ~CFaceOfElement(){} + + /* Alternative constructor to set the corner points. */ + CFaceOfElement(const unsigned short VTK_Type, + const unsigned short nPoly, + const unsigned long *Nodes); + + /* Copy constructor and assignment operator. */ + inline CFaceOfElement(const CFaceOfElement &other) { Copy(other); } + + inline CFaceOfElement& operator=(const CFaceOfElement &other) { Copy(other); return (*this); } + + /* Less than operator. Needed for the sorting and searching. */ + bool operator<(const CFaceOfElement &other) const; + + /* Equal operator. Needed for removing double entities. */ + bool operator ==(const CFaceOfElement &other) const; + + /*--- Member function, which creates a unique numbering for the corner points. + A sort in increasing order is OK for this purpose. ---*/ + inline void CreateUniqueNumbering(void) { std::sort(cornerPoints, cornerPoints+nCornerPoints); } + + /*--- Member function, which creates a unique numbering for the corner points + while the orientation is taken into account. ---*/ + void CreateUniqueNumberingWithOrientation(void); + +private: + /*--- Copy function, which copies the data of the given object into the current object. ---*/ + void Copy(const CFaceOfElement &other); +}; + +/*! + * \class CBoundaryFace + * \brief Help class used in the partitioning of the FEM grid. + It stores a boundary element. + */ +class CBoundaryFace { +public: + unsigned short VTK_Type, nPolyGrid, nDOFsGrid; + unsigned long globalBoundElemID, domainElementID; + std::vector Nodes; + + /* Standard constructor and destructor. Nothing to be done. */ + CBoundaryFace(){} + ~CBoundaryFace(){} + + /* Copy constructor and assignment operator. */ + inline CBoundaryFace(const CBoundaryFace &other) { Copy(other); } + + inline CBoundaryFace& operator=(const CBoundaryFace &other) { Copy(other); return (*this); } + + /* Less than operator. Needed for the sorting. */ + inline bool operator<(const CBoundaryFace &other) const { + return (globalBoundElemID < other.globalBoundElemID); + } + +private: + /*--- Copy function, which copies the data of the given object into the current object. ---*/ + void Copy(const CBoundaryFace &other); +}; + +/*! + * \class CMatchingFace + * \brief Help class used to determine whether or not (periodic) faces match. + */ +class CMatchingFace { +public: + unsigned short nCornerPoints; /*!< \brief Number of corner points of the face. */ + unsigned short nDim; /*!< \brief Number of spatial dimensions. */ + unsigned short nPoly; /*!< \brief Polynomial degree of the face. */ + unsigned short nDOFsElem; /*!< \brief Number of DOFs of the relevant adjacent element. */ + unsigned short elemType; /*!< \brief Type of the adjacent element. */ + unsigned long elemID; /*!< \brief The relevant adjacent element ID. */ + su2double cornerCoor[4][3]; /*!< \brief Coordinates of the corner points of the face. */ + su2double tolForMatching; /*!< \brief Tolerance for this face for matching points. */ + + /* Standard constructor. */ + CMatchingFace(); + + /* Destructor, nothing to be done. */ + ~CMatchingFace(){} + + /* Copy constructor and assignment operator. */ + inline CMatchingFace(const CMatchingFace &other) { Copy(other); } + + inline CMatchingFace& operator=(const CMatchingFace &other) { Copy(other); return (*this); } + + /* Less than operator. Needed for the sorting and searching. */ + bool operator<(const CMatchingFace &other) const; + + /*--- Member function, which sorts the coordinates of the face. ---*/ + void SortFaceCoordinates(void); + +private: + /*--- Copy function, which copies the data of the given object into the current object. ---*/ + void Copy(const CMatchingFace &other); +}; + diff --git a/Common/include/grid_adaptation_structure.hpp b/Common/include/grid_adaptation_structure.hpp index 817716bbf04a..cbfe27694ea8 100644 --- a/Common/include/grid_adaptation_structure.hpp +++ b/Common/include/grid_adaptation_structure.hpp @@ -35,7 +35,7 @@ #include #include -#include "geometry_structure.hpp" +#include "geometry/CPhysicalGeometry.hpp" #include "config_structure.hpp" using namespace std; diff --git a/Common/include/grid_movement_structure.hpp b/Common/include/grid_movement_structure.hpp index e3ce82f9b0f5..a12dabedd2cb 100644 --- a/Common/include/grid_movement_structure.hpp +++ b/Common/include/grid_movement_structure.hpp @@ -38,7 +38,7 @@ #include #include -#include "geometry_structure.hpp" +#include "geometry/CGeometry.hpp" #include "config_structure.hpp" #include "linear_algebra/CSysMatrix.hpp" #include "linear_algebra/CSysVector.hpp" diff --git a/Common/include/interpolation_structure.hpp b/Common/include/interpolation_structure.hpp index 09bbf7d106f4..d76f479c5f2b 100644 --- a/Common/include/interpolation_structure.hpp +++ b/Common/include/interpolation_structure.hpp @@ -37,7 +37,7 @@ #include #include "config_structure.hpp" -#include "geometry_structure.hpp" +#include "geometry/CGeometry.hpp" using namespace std; diff --git a/Common/include/linear_algebra/CMatrixVectorProduct.hpp b/Common/include/linear_algebra/CMatrixVectorProduct.hpp index 02b09b39e807..1458f4c01c59 100644 --- a/Common/include/linear_algebra/CMatrixVectorProduct.hpp +++ b/Common/include/linear_algebra/CMatrixVectorProduct.hpp @@ -30,7 +30,7 @@ #pragma once #include "../config_structure.hpp" -#include "../geometry_structure.hpp" +#include "../geometry/CGeometry.hpp" #include "CSysVector.hpp" #include "CSysMatrix.hpp" diff --git a/Common/include/linear_algebra/CPastixWrapper.hpp b/Common/include/linear_algebra/CPastixWrapper.hpp index 701133ab3ed8..d683e244403b 100644 --- a/Common/include/linear_algebra/CPastixWrapper.hpp +++ b/Common/include/linear_algebra/CPastixWrapper.hpp @@ -31,7 +31,7 @@ #ifdef HAVE_PASTIX #include "../config_structure.hpp" -#include "../geometry_structure.hpp" +#include "../geometry/CGeometry.hpp" namespace PaStiX { extern "C" { diff --git a/Common/include/linear_algebra/CPreconditioner.hpp b/Common/include/linear_algebra/CPreconditioner.hpp index e35502d31d3a..7a55a6f662ce 100644 --- a/Common/include/linear_algebra/CPreconditioner.hpp +++ b/Common/include/linear_algebra/CPreconditioner.hpp @@ -30,7 +30,7 @@ #pragma once #include "../config_structure.hpp" -#include "../geometry_structure.hpp" +#include "../geometry/CGeometry.hpp" #include "CSysVector.hpp" #include "CSysMatrix.hpp" diff --git a/Common/include/linear_algebra/CSysMatrix.hpp b/Common/include/linear_algebra/CSysMatrix.hpp index 5fe835530c96..cebdc1f32293 100644 --- a/Common/include/linear_algebra/CSysMatrix.hpp +++ b/Common/include/linear_algebra/CSysMatrix.hpp @@ -7,7 +7,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2019, SU2 Contributors (cf. AUTHORS.md) @@ -26,7 +26,6 @@ * License along with SU2. If not, see . */ - #pragma once #include "../mpi_structure.hpp" @@ -36,7 +35,7 @@ #include #include "../config_structure.hpp" -#include "../geometry_structure.hpp" +#include "../geometry/CGeometry.hpp" #include "CSysVector.hpp" #include "CPastixWrapper.hpp" diff --git a/Common/include/linear_algebra/CSysSolve.hpp b/Common/include/linear_algebra/CSysSolve.hpp index 5a5c64612aa9..661972f05421 100644 --- a/Common/include/linear_algebra/CSysSolve.hpp +++ b/Common/include/linear_algebra/CSysSolve.hpp @@ -42,7 +42,7 @@ #include "../option_structure.hpp" #include "../config_structure.hpp" -#include "../geometry_structure.hpp" +#include "../geometry/CGeometry.hpp" #include "CSysVector.hpp" #include "CSysMatrix.hpp" #include "CMatrixVectorProduct.hpp" diff --git a/Common/include/toolboxes/C2DContainer.hpp b/Common/include/toolboxes/C2DContainer.hpp index b6be272f8b78..028ff7469af7 100644 --- a/Common/include/toolboxes/C2DContainer.hpp +++ b/Common/include/toolboxes/C2DContainer.hpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2019, SU2 Contributors (cf. AUTHORS.md) diff --git a/Common/lib/Makefile.am b/Common/lib/Makefile.am index d20a545513b1..de5a9c06edc9 100644 --- a/Common/lib/Makefile.am +++ b/Common/lib/Makefile.am @@ -62,8 +62,6 @@ lib_sources = \ ../include/fem_geometry_structure.inl \ ../include/fem_standard_element.hpp \ ../include/fem_standard_element.inl \ - ../include/geometry_structure.hpp \ - ../include/geometry_structure.inl \ ../include/CMultiGridQueue.hpp \ ../include/CMeshReaderFVM.hpp \ ../include/CSU2ASCIIMeshReaderFVM.hpp \ @@ -121,7 +119,6 @@ lib_sources = \ ../src/fem_standard_element.cpp \ ../src/fem_wall_distance.cpp \ ../src/fem_work_estimate_metis.cpp \ - ../src/geometry_structure.cpp \ ../src/CMultiGridQueue.cpp \ ../src/CMeshReaderFVM.cpp \ ../src/CSU2ASCIIMeshReaderFVM.cpp \ @@ -136,6 +133,10 @@ lib_sources = \ ../src/mpi_structure.cpp \ ../src/ad_structure.cpp \ ../src/fem_gauss_jacobi_quadrature.cpp \ + ../src/geometry/CGeometry.cpp \ + ../src/geometry/CPhysicalGeometry.cpp \ + ../src/geometry/CMultiGridGeometry.cpp \ + ../src/geometry/CDummyGeometry.cpp \ ../src/geometry/elements/CElement.cpp \ ../src/geometry/elements/CTRIA1.cpp \ ../src/geometry/elements/CQUAD4.cpp \ diff --git a/Common/src/fem_cgns_elements.cpp b/Common/src/fem_cgns_elements.cpp index c2a03835273c..9937132ef27d 100644 --- a/Common/src/fem_cgns_elements.cpp +++ b/Common/src/fem_cgns_elements.cpp @@ -25,9 +25,16 @@ * License along with SU2. If not, see . */ -#include "../include/geometry_structure.hpp" - #ifdef HAVE_CGNS +#include "../include/fem_cgns_elements.hpp" +#include "../include/geometry_structure_fem_part.hpp" +#include "../include/mpi_structure.hpp" +#include "../include/datatype_structure.hpp" + +#include +#include +#include + #if CGNS_VERSION >= 3300 void CCGNSElementType::DetermineMetaData(const unsigned short nDim, diff --git a/Common/src/geometry/CDummyGeometry.cpp b/Common/src/geometry/CDummyGeometry.cpp new file mode 100644 index 000000000000..bd1a6fe92820 --- /dev/null +++ b/Common/src/geometry/CDummyGeometry.cpp @@ -0,0 +1,148 @@ +/*! + * \file CDummyGeometry.hpp + * \brief Implementation of the dummy geometry class used in "dry run" mode. + * \author T. Albring + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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/geometry/CDummyGeometry.hpp" + + +CDummyGeometry::CDummyGeometry(CConfig *config){ + + size = SU2_MPI::GetSize(); + rank = SU2_MPI::GetRank(); + + nEdge = 0; + nPoint = 0; + nPointDomain = 0; + nPointNode = 0; + nElem = 0; + nMarker = 0; + nZone = config->GetnZone(); + + nElem_Bound = NULL; + Tag_to_Marker = NULL; + elem = NULL; + face = NULL; + bound = NULL; + node = NULL; + edge = NULL; + vertex = NULL; + nVertex = NULL; + newBound = NULL; + nNewElem_Bound = NULL; + Marker_All_SendRecv = NULL; + + XCoordList.clear(); + Xcoord_plane.clear(); + Ycoord_plane.clear(); + Zcoord_plane.clear(); + FaceArea_plane.clear(); + Plane_points.clear(); + + /*--- Arrays for defining the linear partitioning ---*/ + + beg_node = NULL; + end_node = NULL; + + nPointLinear = NULL; + nPointCumulative = NULL; + + /*--- Containers for customized boundary conditions ---*/ + + CustomBoundaryHeatFlux = NULL; //Customized heat flux wall + CustomBoundaryTemperature = NULL; //Customized temperature wall + + /*--- MPI point-to-point data structures ---*/ + + nP2PSend = 0; + nP2PRecv = 0; + + countPerPoint = 0; + + bufD_P2PSend = NULL; + bufD_P2PRecv = NULL; + + bufS_P2PSend = NULL; + bufS_P2PRecv = NULL; + + req_P2PSend = NULL; + req_P2PRecv = NULL; + + nPoint_P2PSend = new int[size]; + nPoint_P2PRecv = new int[size]; + + Neighbors_P2PSend = NULL; + Neighbors_P2PRecv = NULL; + + Local_Point_P2PSend = NULL; + Local_Point_P2PRecv = NULL; + + /*--- MPI periodic data structures ---*/ + + nPeriodicSend = 0; + nPeriodicRecv = 0; + + countPerPeriodicPoint = 0; + + bufD_PeriodicSend = NULL; + bufD_PeriodicRecv = NULL; + + bufS_PeriodicSend = NULL; + bufS_PeriodicRecv = NULL; + + req_PeriodicSend = NULL; + req_PeriodicRecv = NULL; + + nPoint_PeriodicSend = NULL; + nPoint_PeriodicRecv = NULL; + + Neighbors_PeriodicSend = NULL; + Neighbors_PeriodicRecv = NULL; + + Local_Point_PeriodicSend = NULL; + Local_Point_PeriodicRecv = NULL; + + Local_Marker_PeriodicSend = NULL; + Local_Marker_PeriodicRecv = NULL; + + nVertex = new unsigned long[config->GetnMarker_All()]; + + for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ + nVertex[iMarker] = 0; + } + + Tag_to_Marker = new string[config->GetnMarker_All()]; + + for (unsigned short iRank = 0; iRank < size; iRank++){ + nPoint_P2PRecv[iRank] = 0; + nPoint_P2PSend[iRank] = 0; + } + + nDim = CConfig::GetnDim(config->GetMesh_FileName(), config->GetMesh_FileFormat()); + + config->SetnSpanWiseSections(0); +} + +CDummyGeometry::~CDummyGeometry(){} diff --git a/Common/src/geometry/CGeometry.cpp b/Common/src/geometry/CGeometry.cpp new file mode 100644 index 000000000000..23783f7c4e54 --- /dev/null +++ b/Common/src/geometry/CGeometry.cpp @@ -0,0 +1,3964 @@ +/*! + * \file CGeometry.cpp + * \brief Implementation of the base geometry class. + * \author F. Palacios, T. Economon + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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/geometry/CGeometry.hpp" +#include "../../include/geometry/elements/CElement.hpp" + +/*--- Cross product ---*/ + +#define CROSS(dest,v1,v2) \ +(dest)[0] = (v1)[1]*(v2)[2] - (v1)[2]*(v2)[1]; \ +(dest)[1] = (v1)[2]*(v2)[0] - (v1)[0]*(v2)[2]; \ +(dest)[2] = (v1)[0]*(v2)[1] - (v1)[1]*(v2)[0]; + +/*--- Cross product ---*/ + +#define DOT(v1,v2) ((v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2]); + +/*--- a = b - c ---*/ + +#define SUB(dest,v1,v2) \ +(dest)[0] = (v1)[0] - (v2)[0]; \ +(dest)[1] = (v1)[1] - (v2)[1]; \ +(dest)[2] = (v1)[2] - (v2)[2]; + +CGeometry::CGeometry(void) { + + size = SU2_MPI::GetSize(); + rank = SU2_MPI::GetRank(); + + nEdge = 0; + nPoint = 0; + nPointNode = 0; + nElem = 0; + + nElem_Bound = NULL; + Tag_to_Marker = NULL; + elem = NULL; + face = NULL; + bound = NULL; + node = NULL; + edge = NULL; + vertex = NULL; + nVertex = NULL; + newBound = NULL; + nNewElem_Bound = NULL; + Marker_All_SendRecv = NULL; + + XCoordList.clear(); + Xcoord_plane.clear(); + Ycoord_plane.clear(); + Zcoord_plane.clear(); + FaceArea_plane.clear(); + Plane_points.clear(); + + /*--- Arrays for defining the linear partitioning ---*/ + + beg_node = NULL; + end_node = NULL; + + nPointLinear = NULL; + nPointCumulative = NULL; + + /*--- Containers for customized boundary conditions ---*/ + + CustomBoundaryHeatFlux = NULL; //Customized heat flux wall + CustomBoundaryTemperature = NULL; //Customized temperature wall + + /*--- MPI point-to-point data structures ---*/ + + nP2PSend = 0; + nP2PRecv = 0; + + countPerPoint = 0; + + bufD_P2PSend = NULL; + bufD_P2PRecv = NULL; + + bufS_P2PSend = NULL; + bufS_P2PRecv = NULL; + + req_P2PSend = NULL; + req_P2PRecv = NULL; + + nPoint_P2PSend = NULL; + nPoint_P2PRecv = NULL; + + Neighbors_P2PSend = NULL; + Neighbors_P2PRecv = NULL; + + Local_Point_P2PSend = NULL; + Local_Point_P2PRecv = NULL; + + /*--- MPI periodic data structures ---*/ + + nPeriodicSend = 0; + nPeriodicRecv = 0; + + countPerPeriodicPoint = 0; + + bufD_PeriodicSend = NULL; + bufD_PeriodicRecv = NULL; + + bufS_PeriodicSend = NULL; + bufS_PeriodicRecv = NULL; + + req_PeriodicSend = NULL; + req_PeriodicRecv = NULL; + + nPoint_PeriodicSend = NULL; + nPoint_PeriodicRecv = NULL; + + Neighbors_PeriodicSend = NULL; + Neighbors_PeriodicRecv = NULL; + + Local_Point_PeriodicSend = NULL; + Local_Point_PeriodicRecv = NULL; + + Local_Marker_PeriodicSend = NULL; + Local_Marker_PeriodicRecv = NULL; + +} + +CGeometry::~CGeometry(void) { + + unsigned long iElem, iElem_Bound, iEdge, iFace, iPoint, iVertex; + unsigned short iMarker; + + if (elem != NULL) { + for (iElem = 0; iElem < nElem; iElem++) + if (elem[iElem] != NULL) delete elem[iElem]; + delete[] elem; + } + + if (bound != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound]; + } + if (bound[iMarker] != NULL) delete [] bound[iMarker]; + } + delete [] bound; + } + + if (face != NULL) { + for (iFace = 0; iFace < nFace; iFace ++) + if (face[iFace] != NULL) delete face[iFace]; + delete[] face; + } + + if (node != NULL) { + for (iPoint = 0; iPoint < nPointNode; iPoint ++) + if (node[iPoint] != NULL) delete node[iPoint]; + delete[] node; + } + + + if (edge != NULL) { + for (iEdge = 0; iEdge < nEdge; iEdge ++) + if (edge[iEdge] != NULL) delete edge[iEdge]; + delete[] edge; + } + + if (vertex != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + if (vertex[iMarker][iVertex] != NULL) delete vertex[iMarker][iVertex]; + } + if (vertex[iMarker] != NULL) delete [] vertex[iMarker]; + } + delete [] vertex; + } + + if (newBound != NULL) { + for (iMarker = 0; iMarker < nMarker; iMarker++) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (newBound[iMarker][iElem_Bound] != NULL) delete [] newBound[iMarker][iElem_Bound]; + } + delete[] newBound[iMarker]; + } + delete[] newBound; + } + + if (nElem_Bound != NULL) delete [] nElem_Bound; + if (nVertex != NULL) delete [] nVertex; + if (nNewElem_Bound != NULL) delete [] nNewElem_Bound; + if (Marker_All_SendRecv != NULL) delete [] Marker_All_SendRecv; + if (Tag_to_Marker != NULL) delete [] Tag_to_Marker; + + if (beg_node != NULL) delete [] beg_node; + if (end_node != NULL) delete [] end_node; + if (nPointLinear != NULL) delete [] nPointLinear; + if (nPointCumulative != NULL) delete [] nPointCumulative; + + if(CustomBoundaryHeatFlux != NULL){ + for(iMarker=0; iMarker < nMarker; iMarker++){ + if (CustomBoundaryHeatFlux[iMarker] != NULL) delete [] CustomBoundaryHeatFlux[iMarker]; + } + delete [] CustomBoundaryHeatFlux; + } + + if(CustomBoundaryTemperature != NULL){ + for(iMarker=0; iMarker < nMarker; iMarker++){ + if(CustomBoundaryTemperature[iMarker] != NULL) delete [] CustomBoundaryTemperature[iMarker]; + } + delete [] CustomBoundaryTemperature; + } + + /*--- Delete structures for MPI point-to-point communication. ---*/ + + if (bufD_P2PRecv != NULL) delete [] bufD_P2PRecv; + if (bufD_P2PSend != NULL) delete [] bufD_P2PSend; + + if (bufS_P2PRecv != NULL) delete [] bufS_P2PRecv; + if (bufS_P2PSend != NULL) delete [] bufS_P2PSend; + + if (req_P2PSend != NULL) delete [] req_P2PSend; + if (req_P2PRecv != NULL) delete [] req_P2PRecv; + + if (nPoint_P2PRecv != NULL) delete [] nPoint_P2PRecv; + if (nPoint_P2PSend != NULL) delete [] nPoint_P2PSend; + + if (Neighbors_P2PSend != NULL) delete [] Neighbors_P2PSend; + if (Neighbors_P2PRecv != NULL) delete [] Neighbors_P2PRecv; + + if (Local_Point_P2PSend != NULL) delete [] Local_Point_P2PSend; + if (Local_Point_P2PRecv != NULL) delete [] Local_Point_P2PRecv; + + /*--- Delete structures for MPI periodic communication. ---*/ + + if (bufD_PeriodicRecv != NULL) delete [] bufD_PeriodicRecv; + if (bufD_PeriodicSend != NULL) delete [] bufD_PeriodicSend; + + if (bufS_PeriodicRecv != NULL) delete [] bufS_PeriodicRecv; + if (bufS_PeriodicSend != NULL) delete [] bufS_PeriodicSend; + + if (req_PeriodicSend != NULL) delete [] req_PeriodicSend; + if (req_PeriodicRecv != NULL) delete [] req_PeriodicRecv; + + if (nPoint_PeriodicRecv != NULL) delete [] nPoint_PeriodicRecv; + if (nPoint_PeriodicSend != NULL) delete [] nPoint_PeriodicSend; + + if (Neighbors_PeriodicSend != NULL) delete [] Neighbors_PeriodicSend; + if (Neighbors_PeriodicRecv != NULL) delete [] Neighbors_PeriodicRecv; + + if (Local_Point_PeriodicSend != NULL) delete [] Local_Point_PeriodicSend; + if (Local_Point_PeriodicRecv != NULL) delete [] Local_Point_PeriodicRecv; + + if (Local_Marker_PeriodicSend != NULL) delete [] Local_Marker_PeriodicSend; + if (Local_Marker_PeriodicRecv != NULL) delete [] Local_Marker_PeriodicRecv; + +} + +void CGeometry::PreprocessP2PComms(CGeometry *geometry, + CConfig *config) { + + /*--- We start with the send and receive lists already available in + the form of SEND_RECEIVE boundary markers. We will loop through + these markers and establish the neighboring ranks and number of + send/recv points per pair. We will store this information and set + up persistent data structures so that we can reuse them throughout + the calculation for any point-to-point communications. The goal + is to break the non-blocking comms into InitiateComms() and + CompleteComms() in separate routines so that we can overlap the + communication and computation to hide the communication latency. ---*/ + + /*--- Local variables. ---*/ + + unsigned short iMarker; + unsigned long nVertexS, nVertexR, iVertex, MarkerS, MarkerR; + + int iRank, iSend, iRecv, count; + + /*--- Create some temporary structures for tracking sends/recvs. ---*/ + + int *nPoint_Send_All = new int[size+1]; nPoint_Send_All[0] = 0; + int *nPoint_Recv_All = new int[size+1]; nPoint_Recv_All[0] = 0; + int *nPoint_Flag = new int[size]; + + for (iRank = 0; iRank < size; iRank++) { + nPoint_Send_All[iRank] = 0; nPoint_Recv_All[iRank] = 0; nPoint_Flag[iRank]= -1; + } + nPoint_Send_All[size] = 0; nPoint_Recv_All[size] = 0; + + /*--- Loop through all of our SEND_RECEIVE markers and track + our sends with each rank. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + /*--- Get the destination rank and number of points to send. ---*/ + + iRank = config->GetMarker_All_SendRecv(iMarker)-1; + nVertexS = geometry->nVertex[iMarker]; + + /*--- 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; + nPoint_Send_All[iRank+1] += nVertexS; + } + + } + } + + delete [] nPoint_Flag; + + /*--- Communicate the number of points to be sent/recv'd amongst + all processors. After this communication, each proc knows how + many cells it will receive from each other processor. ---*/ + + SU2_MPI::Alltoall(&(nPoint_Send_All[1]), 1, MPI_INT, + &(nPoint_Recv_All[1]), 1, MPI_INT, MPI_COMM_WORLD); + + /*--- Prepare to send connectivities. First check how many + messages we will be sending and receiving. Here we also put + the counters into cumulative storage format to make the + communications simpler. ---*/ + + nP2PSend = 0; nP2PRecv = 0; + + for (iRank = 0; iRank < size; iRank++) { + if ((iRank != rank) && (nPoint_Send_All[iRank+1] > 0)) nP2PSend++; + if ((iRank != rank) && (nPoint_Recv_All[iRank+1] > 0)) nP2PRecv++; + + nPoint_Send_All[iRank+1] += nPoint_Send_All[iRank]; + nPoint_Recv_All[iRank+1] += nPoint_Recv_All[iRank]; + } + + /*--- Allocate only as much memory as we need for the P2P neighbors. ---*/ + + nPoint_P2PSend = new int[nP2PSend+1]; nPoint_P2PSend[0] = 0; + nPoint_P2PRecv = new int[nP2PRecv+1]; nPoint_P2PRecv[0] = 0; + + Neighbors_P2PSend = new int[nP2PSend]; + Neighbors_P2PRecv = new int[nP2PRecv]; + + iSend = 0; iRecv = 0; + for (iRank = 0; iRank < size; iRank++) { + + if ((nPoint_Send_All[iRank+1] > nPoint_Send_All[iRank]) && (iRank != rank)) { + Neighbors_P2PSend[iSend] = iRank; + nPoint_P2PSend[iSend+1] = nPoint_Send_All[iRank+1]; + iSend++; + } + + if ((nPoint_Recv_All[iRank+1] > nPoint_Recv_All[iRank]) && (iRank != rank)) { + Neighbors_P2PRecv[iRecv] = iRank; + nPoint_P2PRecv[iRecv+1] = nPoint_Recv_All[iRank+1]; + iRecv++; + } + + } + + /*--- Create a reverse mapping of the message to the rank so that we + can quickly access the correct data in the buffers when receiving + messages dynamically. ---*/ + + P2PSend2Neighbor.clear(); + for (iSend = 0; iSend < nP2PSend; iSend++) + P2PSend2Neighbor[Neighbors_P2PSend[iSend]] = iSend; + + P2PRecv2Neighbor.clear(); + for (iRecv = 0; iRecv < nP2PRecv; iRecv++) + P2PRecv2Neighbor[Neighbors_P2PRecv[iRecv]] = iRecv; + + delete [] nPoint_Send_All; + delete [] nPoint_Recv_All; + + /*--- Allocate the memory that we need for receiving the conn + values and then cue up the non-blocking receives. Note that + we do not include our own rank in the communications. We will + directly copy our own data later. ---*/ + + Local_Point_P2PSend = NULL; + Local_Point_P2PSend = new unsigned long[nPoint_P2PSend[nP2PSend]]; + for (iSend = 0; iSend < nPoint_P2PSend[nP2PSend]; iSend++) + Local_Point_P2PSend[iSend] = 0; + + Local_Point_P2PRecv = NULL; + Local_Point_P2PRecv = new unsigned long[nPoint_P2PRecv[nP2PRecv]]; + for (iRecv = 0; iRecv < nPoint_P2PRecv[nP2PRecv]; iRecv++) + Local_Point_P2PRecv[iRecv] = 0; + + /*--- We allocate the memory for communicating values in a later step + once we know the maximum packet size that we need to communicate. This + memory is deallocated and reallocated automatically in the case that + the previously allocated memory is not sufficient. ---*/ + + bufD_P2PSend = NULL; + bufD_P2PRecv = NULL; + + bufS_P2PSend = NULL; + bufS_P2PRecv = NULL; + + /*--- Allocate memory for the MPI requests if we need to communicate. ---*/ + + if (nP2PSend > 0) { + req_P2PSend = new SU2_MPI::Request[nP2PSend]; + } + if (nP2PRecv > 0) { + req_P2PRecv = new SU2_MPI::Request[nP2PRecv]; + } + + /*--- Build lists of local index values for send. ---*/ + + count = 0; + for (iSend = 0; iSend < nP2PSend; iSend++) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; + nVertexS = geometry->nVertex[MarkerS]; + iRank = config->GetMarker_All_SendRecv(MarkerS)-1; + + if (iRank == Neighbors_P2PSend[iSend]) { + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + Local_Point_P2PSend[count] = geometry->vertex[MarkerS][iVertex]->GetNode(); + count++; + } + } + + } + } + } + + /*--- Build lists of local index values for receive. ---*/ + + count = 0; + for (iRecv = 0; iRecv < nP2PRecv; iRecv++) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerR = iMarker+1; + nVertexR = geometry->nVertex[MarkerR]; + iRank = abs(config->GetMarker_All_SendRecv(MarkerR))-1; + + if (iRank == Neighbors_P2PRecv[iRecv]) { + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + Local_Point_P2PRecv[count] = geometry->vertex[MarkerR][iVertex]->GetNode(); + count++; + } + } + + } + } + } + + /*--- In the future, some additional data structures could be created + here to separate the interior and boundary nodes in order to help + further overlap computation and communication. ---*/ + +} + +void CGeometry::AllocateP2PComms(unsigned short val_countPerPoint) { + + /*--- This routine is activated whenever we attempt to perform + a point-to-point MPI communication with our neighbors but the + memory buffer allocated is not large enough for the packet size. + Therefore, we deallocate the previously allocated space and + reallocate a large enough array. Note that after the first set + communications, this routine will not need to be called again. ---*/ + + int iSend, iRecv; + + /*--- Store the larger packet size to the class data. ---*/ + + countPerPoint = val_countPerPoint; + + /*-- Deallocate and reallocate our su2double cummunication memory. ---*/ + + if (bufD_P2PSend != NULL) delete [] bufD_P2PSend; + + bufD_P2PSend = new su2double[countPerPoint*nPoint_P2PSend[nP2PSend]]; + for (iSend = 0; iSend < countPerPoint*nPoint_P2PSend[nP2PSend]; iSend++) + bufD_P2PSend[iSend] = 0.0; + + if (bufD_P2PRecv != NULL) delete [] bufD_P2PRecv; + + bufD_P2PRecv = new su2double[countPerPoint*nPoint_P2PRecv[nP2PRecv]]; + for (iRecv = 0; iRecv < countPerPoint*nPoint_P2PRecv[nP2PRecv]; iRecv++) + bufD_P2PRecv[iRecv] = 0.0; + + if (bufS_P2PSend != NULL) delete [] bufS_P2PSend; + + bufS_P2PSend = new unsigned short[countPerPoint*nPoint_P2PSend[nP2PSend]]; + for (iSend = 0; iSend < countPerPoint*nPoint_P2PSend[nP2PSend]; iSend++) + bufS_P2PSend[iSend] = 0; + + if (bufS_P2PRecv != NULL) delete [] bufS_P2PRecv; + + bufS_P2PRecv = new unsigned short[countPerPoint*nPoint_P2PRecv[nP2PRecv]]; + for (iRecv = 0; iRecv < countPerPoint*nPoint_P2PRecv[nP2PRecv]; iRecv++) + bufS_P2PRecv[iRecv] = 0; + +} + +void CGeometry::PostP2PRecvs(CGeometry *geometry, + CConfig *config, + unsigned short commType, + bool val_reverse) { + + /*--- Local variables ---*/ + + int iMessage, iRecv, offset, nPointP2P, count, source, tag; + + /*--- Launch the non-blocking recv's first. Note that we have stored + the counts and sources, so we can launch these before we even load + the data and send from the neighbor ranks. ---*/ + + iMessage = 0; + for (iRecv = 0; iRecv < nP2PRecv; iRecv++) { + + /*--- In some instances related to the adjoint solver, we need + to reverse the direction of communications such that the normal + send nodes become the recv nodes and vice-versa. ---*/ + + if (val_reverse) { + + /*--- Compute our location in the buffer using the send data + structure since we are reversing the comms. ---*/ + + offset = countPerPoint*nPoint_P2PSend[iRecv]; + + /*--- Take advantage of cumulative storage format to get the number + of elems that we need to recv. Note again that we select the send + points here as the recv points. ---*/ + + nPointP2P = nPoint_P2PSend[iRecv+1] - nPoint_P2PSend[iRecv]; + + /*--- Total count can include multiple pieces of data per element. ---*/ + + count = countPerPoint*nPointP2P; + + /*--- Get the rank from which we receive the message. Note again + that we use the send rank as the source instead of the recv rank. ---*/ + + source = Neighbors_P2PSend[iRecv]; + tag = source + 1; + + /*--- Post non-blocking recv for this proc. Note that we use the + send buffer here too. This is important to make sure the arrays + are the correct size. ---*/ + + switch (commType) { + case COMM_TYPE_DOUBLE: + SU2_MPI::Irecv(&(bufD_P2PSend[offset]), count, MPI_DOUBLE, + source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); + break; + case COMM_TYPE_UNSIGNED_SHORT: + SU2_MPI::Irecv(&(bufS_P2PSend[offset]), count, MPI_UNSIGNED_SHORT, + source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); + break; + default: + SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + + } else { + + /*--- Compute our location in the recv buffer. ---*/ + + offset = countPerPoint*nPoint_P2PRecv[iRecv]; + + /*--- Take advantage of cumulative storage format to get the number + of elems that we need to recv. ---*/ + + nPointP2P = nPoint_P2PRecv[iRecv+1] - nPoint_P2PRecv[iRecv]; + + /*--- Total count can include multiple pieces of data per element. ---*/ + + count = countPerPoint*nPointP2P; + + /*--- Get the rank from which we receive the message. ---*/ + + source = Neighbors_P2PRecv[iRecv]; + tag = source + 1; + + /*--- Post non-blocking recv for this proc. ---*/ + + switch (commType) { + case COMM_TYPE_DOUBLE: + SU2_MPI::Irecv(&(bufD_P2PRecv[offset]), count, MPI_DOUBLE, + source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); + break; + case COMM_TYPE_UNSIGNED_SHORT: + SU2_MPI::Irecv(&(bufS_P2PRecv[offset]), count, MPI_UNSIGNED_SHORT, + source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); + break; + default: + SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + + } + + /*--- Increment message counter. ---*/ + + iMessage++; + + } + +} + +void CGeometry::PostP2PSends(CGeometry *geometry, + CConfig *config, + unsigned short commType, + int val_iSend, + bool val_reverse) { + + /*--- Local variables ---*/ + + int iMessage, offset, nPointP2P, count, dest, tag; + + /*--- Post the non-blocking send as soon as the buffer is loaded. ---*/ + + iMessage = val_iSend; + + /*--- In some instances related to the adjoint solver, we need + to reverse the direction of communications such that the normal + send nodes become the recv nodes and vice-versa. ---*/ + + if (val_reverse) { + + /*--- Compute our location in the buffer using the recv data + structure since we are reversing the comms. ---*/ + + offset = countPerPoint*nPoint_P2PRecv[val_iSend]; + + /*--- Take advantage of cumulative storage format to get the number + of points that we need to send. Note again that we select the recv + points here as the send points. ---*/ + + nPointP2P = nPoint_P2PRecv[val_iSend+1] - nPoint_P2PRecv[val_iSend]; + + /*--- Total count can include multiple pieces of data per element. ---*/ + + count = countPerPoint*nPointP2P; + + /*--- Get the rank to which we send the message. Note again + that we use the recv rank as the dest instead of the send rank. ---*/ + + dest = Neighbors_P2PRecv[val_iSend]; + tag = rank + 1; + + /*--- Post non-blocking send for this proc. Note that we use the + send buffer here too. This is important to make sure the arrays + are the correct size. ---*/ + + switch (commType) { + case COMM_TYPE_DOUBLE: + SU2_MPI::Isend(&(bufD_P2PRecv[offset]), count, MPI_DOUBLE, + dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); + break; + case COMM_TYPE_UNSIGNED_SHORT: + SU2_MPI::Isend(&(bufS_P2PRecv[offset]), count, MPI_UNSIGNED_SHORT, + dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); + break; + default: + SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + + } else { + + /*--- Compute our location in the send buffer. ---*/ + + offset = countPerPoint*nPoint_P2PSend[val_iSend]; + + /*--- Take advantage of cumulative storage format to get the number + of points that we need to send. ---*/ + + nPointP2P = nPoint_P2PSend[val_iSend+1] - nPoint_P2PSend[val_iSend]; + + /*--- Total count can include multiple pieces of data per element. ---*/ + + count = countPerPoint*nPointP2P; + + /*--- Get the rank to which we send the message. ---*/ + + dest = Neighbors_P2PSend[val_iSend]; + tag = rank + 1; + + /*--- Post non-blocking send for this proc. ---*/ + + switch (commType) { + case COMM_TYPE_DOUBLE: + SU2_MPI::Isend(&(bufD_P2PSend[offset]), count, MPI_DOUBLE, + dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); + break; + case COMM_TYPE_UNSIGNED_SHORT: + SU2_MPI::Isend(&(bufS_P2PSend[offset]), count, MPI_UNSIGNED_SHORT, + dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); + break; + default: + SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + + } + +} + +void CGeometry::InitiateComms(CGeometry *geometry, + CConfig *config, + unsigned short commType) { + + /*--- Local variables ---*/ + + unsigned short iDim; + unsigned short COUNT_PER_POINT = 0; + unsigned short MPI_TYPE = 0; + + unsigned long iPoint, msg_offset, buf_offset; + + int iMessage, iSend, nSend; + + /*--- Set the size of the data packet and type depending on quantity. ---*/ + + switch (commType) { + case COORDINATES: + COUNT_PER_POINT = nDim; + MPI_TYPE = COMM_TYPE_DOUBLE; + break; + case GRID_VELOCITY: + COUNT_PER_POINT = nDim; + MPI_TYPE = COMM_TYPE_DOUBLE; + break; + case COORDINATES_OLD: + if (config->GetTime_Marching() == DT_STEPPING_2ND) + COUNT_PER_POINT = nDim*2; + else + COUNT_PER_POINT = nDim; + MPI_TYPE = COMM_TYPE_DOUBLE; + break; + case MAX_LENGTH: + COUNT_PER_POINT = 1; + MPI_TYPE = COMM_TYPE_DOUBLE; + break; + case NEIGHBORS: + COUNT_PER_POINT = 1; + MPI_TYPE = COMM_TYPE_UNSIGNED_SHORT; + break; + default: + SU2_MPI::Error("Unrecognized quantity for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + + /*--- Check to make sure we have created a large enough buffer + for these comms during preprocessing. This is only for the su2double + buffer. It will be reallocated whenever we find a larger count + per point. After the first cycle of comms, this should be inactive. ---*/ + + if (COUNT_PER_POINT > geometry->countPerPoint) { + geometry->AllocateP2PComms(COUNT_PER_POINT); + } + + /*--- Set some local pointers to make access simpler. ---*/ + + su2double *bufDSend = geometry->bufD_P2PSend; + unsigned short *bufSSend = geometry->bufS_P2PSend; + + su2double *vector = NULL; + + /*--- Load the specified quantity from the solver into the generic + communication buffer in the geometry class. ---*/ + + if (nP2PSend > 0) { + + /*--- Post all non-blocking recvs first before sends. ---*/ + + geometry->PostP2PRecvs(geometry, config, MPI_TYPE, false); + + for (iMessage = 0; iMessage < nP2PSend; iMessage++) { + + /*--- Get the offset in the buffer for the start of this message. ---*/ + + msg_offset = nPoint_P2PSend[iMessage]; + + /*--- Total count can include multiple pieces of data per element. ---*/ + + nSend = (nPoint_P2PSend[iMessage+1] - nPoint_P2PSend[iMessage]); + + for (iSend = 0; iSend < nSend; iSend++) { + + /*--- Get the local index for this communicated data. ---*/ + + iPoint = geometry->Local_Point_P2PSend[msg_offset + iSend]; + + /*--- Compute the offset in the recv buffer for this point. ---*/ + + buf_offset = (msg_offset + iSend)*countPerPoint; + + switch (commType) { + case COORDINATES: + vector = node[iPoint]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) + bufDSend[buf_offset+iDim] = vector[iDim]; + break; + case GRID_VELOCITY: + vector = node[iPoint]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + bufDSend[buf_offset+iDim] = vector[iDim]; + break; + case COORDINATES_OLD: + vector = node[iPoint]->GetCoord_n(); + for (iDim = 0; iDim < nDim; iDim++) { + bufDSend[buf_offset+iDim] = vector[iDim]; + } + if (config->GetTime_Marching() == DT_STEPPING_2ND) { + vector = node[iPoint]->GetCoord_n1(); + for (iDim = 0; iDim < nDim; iDim++) { + bufDSend[buf_offset+nDim+iDim] = vector[iDim]; + } + } + break; + case MAX_LENGTH: + bufDSend[buf_offset] = node[iPoint]->GetMaxLength(); + break; + case NEIGHBORS: + bufSSend[buf_offset] = geometry->node[iPoint]->GetnNeighbor(); + break; + default: + SU2_MPI::Error("Unrecognized quantity for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + } + + /*--- Launch the point-to-point MPI send for this message. ---*/ + + geometry->PostP2PSends(geometry, config, MPI_TYPE, iMessage, false); + + } + } + +} + +void CGeometry::CompleteComms(CGeometry *geometry, + CConfig *config, + unsigned short commType) { + + /*--- Local variables ---*/ + + unsigned short iDim; + unsigned long iPoint, iRecv, nRecv, msg_offset, buf_offset; + + int ind, source, iMessage, jRecv; + SU2_MPI::Status status; + + /*--- Set some local pointers to make access simpler. ---*/ + + su2double *bufDRecv = geometry->bufD_P2PRecv; + unsigned short *bufSRecv = geometry->bufS_P2PRecv; + + /*--- Store the data that was communicated into the appropriate + location within the local class data structures. Note that we + recv and store the data in any order to take advantage of the + non-blocking comms. ---*/ + + if (nP2PRecv > 0) { + + for (iMessage = 0; iMessage < nP2PRecv; iMessage++) { + + /*--- For efficiency, recv the messages dynamically based on + the order they arrive. ---*/ + + SU2_MPI::Waitany(nP2PRecv, req_P2PRecv, &ind, &status); + + /*--- Once we have recv'd a message, get the source rank. ---*/ + + source = status.MPI_SOURCE; + + /*--- We know the offsets based on the source rank. ---*/ + + jRecv = P2PRecv2Neighbor[source]; + + /*--- Get the offset in the buffer for the start of this message. ---*/ + + msg_offset = nPoint_P2PRecv[jRecv]; + + /*--- Get the number of packets to be received in this message. ---*/ + + nRecv = nPoint_P2PRecv[jRecv+1] - nPoint_P2PRecv[jRecv]; + + for (iRecv = 0; iRecv < nRecv; iRecv++) { + + /*--- Get the local index for this communicated data. ---*/ + + iPoint = geometry->Local_Point_P2PRecv[msg_offset + iRecv]; + + /*--- Compute the total offset in the recv buffer for this point. ---*/ + + buf_offset = (msg_offset + iRecv)*countPerPoint; + + /*--- Store the data correctly depending on the quantity. ---*/ + + switch (commType) { + case COORDINATES: + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetCoord(iDim, bufDRecv[buf_offset+iDim]); + break; + case GRID_VELOCITY: + for (iDim = 0; iDim < nDim; iDim++) + node[iPoint]->SetGridVel(iDim, bufDRecv[buf_offset+iDim]); + break; + case COORDINATES_OLD: + node[iPoint]->SetCoord_n(&bufDRecv[buf_offset]); + if (config->GetTime_Marching() == DT_STEPPING_2ND) + node[iPoint]->SetCoord_n1(&bufDRecv[buf_offset+nDim]); + break; + case MAX_LENGTH: + node[iPoint]->SetMaxLength(bufDRecv[buf_offset]); + break; + case NEIGHBORS: + node[iPoint]->SetnNeighbor(bufSRecv[buf_offset]); + break; + default: + SU2_MPI::Error("Unrecognized quantity for point-to-point MPI comms.", + CURRENT_FUNCTION); + break; + } + } + } + + /*--- Verify that all non-blocking point-to-point sends have finished. + Note that this should be satisfied, as we have received all of the + data in the loop above at this point. ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Waitall(nP2PSend, req_P2PSend, MPI_STATUS_IGNORE); +#endif + + } + +} + +void CGeometry::PreprocessPeriodicComms(CGeometry *geometry, + CConfig *config) { + + /*--- We start with the send and receive lists already available in + the form of stored periodic point-donor pairs. We will loop through + these markers and establish the neighboring ranks and number of + send/recv points per pair. We will store this information and set + up persistent data structures so that we can reuse them throughout + the calculation for any periodic boundary communications. The goal + is to break the non-blocking comms into InitiatePeriodicComms() and + CompletePeriodicComms() in separate routines so that we can overlap the + communication and computation to hide the communication latency. ---*/ + + /*--- Local variables. ---*/ + + unsigned short iMarker; + unsigned long iPoint, iVertex, iPeriodic; + + int iRank, iSend, iRecv, ii, jj; + + /*--- Create some temporary structures for tracking sends/recvs. ---*/ + + int *nPoint_Send_All = new int[size+1]; nPoint_Send_All[0] = 0; + int *nPoint_Recv_All = new int[size+1]; nPoint_Recv_All[0] = 0; + int *nPoint_Flag = new int[size]; + + for (iRank = 0; iRank < size; iRank++) { + nPoint_Send_All[iRank] = 0; + nPoint_Recv_All[iRank] = 0; + nPoint_Flag[iRank]= -1; + } + nPoint_Send_All[size] = 0; nPoint_Recv_All[size] = 0; + + /*--- Loop through all of our periodic markers and track + our sends with each rank. ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + iPeriodic = config->GetMarker_All_PerBound(iMarker); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Get the current periodic point index. We only communicate + the owned nodes on a rank, as the MPI comms will take care of + the halos after completing the periodic comms. ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Get the rank that holds the matching periodic point + on the other marker in the periodic pair. ---*/ + + iRank = (int)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; + nPoint_Send_All[iRank+1] += 1; + } + + } + } + } + } + + delete [] nPoint_Flag; + + /*--- Communicate the number of points to be sent/recv'd amongst + all processors. After this communication, each proc knows how + many periodic points it will receive from each other processor. ---*/ + + SU2_MPI::Alltoall(&(nPoint_Send_All[1]), 1, MPI_INT, + &(nPoint_Recv_All[1]), 1, MPI_INT, MPI_COMM_WORLD); + + /*--- Check how many messages we will be sending and receiving. + Here we also put the counters into cumulative storage format to + make the communications simpler. Note that we are allowing each + rank to communicate to themselves in these counters, although + it will not be done through MPI. ---*/ + + nPeriodicSend = 0; nPeriodicRecv = 0; + + for (iRank = 0; iRank < size; iRank++) { + if ((nPoint_Send_All[iRank+1] > 0)) nPeriodicSend++; + if ((nPoint_Recv_All[iRank+1] > 0)) nPeriodicRecv++; + + nPoint_Send_All[iRank+1] += nPoint_Send_All[iRank]; + nPoint_Recv_All[iRank+1] += nPoint_Recv_All[iRank]; + } + + /*--- Allocate only as much memory as needed for the periodic neighbors. ---*/ + + nPoint_PeriodicSend = new int[nPeriodicSend+1]; nPoint_PeriodicSend[0] = 0; + nPoint_PeriodicRecv = new int[nPeriodicRecv+1]; nPoint_PeriodicRecv[0] = 0; + + Neighbors_PeriodicSend = new int[nPeriodicSend]; + Neighbors_PeriodicRecv = new int[nPeriodicRecv]; + + iSend = 0; iRecv = 0; + for (iRank = 0; iRank < size; iRank++) { + if ((nPoint_Send_All[iRank+1] > nPoint_Send_All[iRank])) { + Neighbors_PeriodicSend[iSend] = iRank; + nPoint_PeriodicSend[iSend+1] = nPoint_Send_All[iRank+1]; + iSend++; + } + if ((nPoint_Recv_All[iRank+1] > nPoint_Recv_All[iRank])) { + Neighbors_PeriodicRecv[iRecv] = iRank; + nPoint_PeriodicRecv[iRecv+1] = nPoint_Recv_All[iRank+1]; + iRecv++; + } + } + + /*--- Create a reverse mapping of the message to the rank so that we + can quickly access the correct data in the buffers when receiving + messages dynamically later during the iterations. ---*/ + + PeriodicSend2Neighbor.clear(); + for (iSend = 0; iSend < nPeriodicSend; iSend++) + PeriodicSend2Neighbor[Neighbors_PeriodicSend[iSend]] = iSend; + + PeriodicRecv2Neighbor.clear(); + for (iRecv = 0; iRecv < nPeriodicRecv; iRecv++) + PeriodicRecv2Neighbor[Neighbors_PeriodicRecv[iRecv]] = iRecv; + + delete [] nPoint_Send_All; + delete [] nPoint_Recv_All; + + /*--- Allocate the memory to store the local index values for both + the send and receive periodic points and periodic index. ---*/ + + Local_Point_PeriodicSend = NULL; + Local_Point_PeriodicSend = new unsigned long[nPoint_PeriodicSend[nPeriodicSend]]; + for (iSend = 0; iSend < nPoint_PeriodicSend[nPeriodicSend]; iSend++) + Local_Point_PeriodicSend[iSend] = 0; + + Local_Marker_PeriodicSend = NULL; + Local_Marker_PeriodicSend = new unsigned long[nPoint_PeriodicSend[nPeriodicSend]]; + for (iSend = 0; iSend < nPoint_PeriodicSend[nPeriodicSend]; iSend++) + Local_Marker_PeriodicSend[iSend] = 0; + + Local_Point_PeriodicRecv = NULL; + Local_Point_PeriodicRecv = new unsigned long[nPoint_PeriodicRecv[nPeriodicRecv]]; + for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]; iRecv++) + Local_Point_PeriodicRecv[iRecv] = 0; + + Local_Marker_PeriodicRecv = NULL; + Local_Marker_PeriodicRecv = new unsigned long[nPoint_PeriodicRecv[nPeriodicRecv]]; + for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]; iRecv++) + Local_Marker_PeriodicRecv[iRecv] = 0; + + /*--- We allocate the buffers for communicating values in a later step + once we know the maximum packet size that we need to communicate. This + memory is deallocated and reallocated automatically in the case that + the previously allocated memory is not sufficient. ---*/ + + bufD_PeriodicSend = NULL; + bufD_PeriodicRecv = NULL; + + bufS_PeriodicSend = NULL; + bufS_PeriodicRecv = NULL; + + /*--- Allocate memory for the MPI requests if we need to communicate. ---*/ + + if (nPeriodicSend > 0) { + req_PeriodicSend = new SU2_MPI::Request[nPeriodicSend]; + } + if (nPeriodicRecv > 0) { + req_PeriodicRecv = new SU2_MPI::Request[nPeriodicRecv]; + } + + /*--- Allocate arrays for sending the periodic point index and marker + index to the recv rank so that it can store the local values. Therefore, + the recv rank can quickly loop through the buffers to unpack the data. ---*/ + + unsigned short nPackets = 2; + unsigned long *idSend = new unsigned long[nPoint_PeriodicSend[nPeriodicSend]*nPackets]; + for (iSend = 0; iSend < nPoint_PeriodicSend[nPeriodicSend]*nPackets; iSend++) + idSend[iSend] = 0; + + /*--- Build the lists of local index and periodic marker index values. ---*/ + + ii = 0; jj = 0; + for (iSend = 0; iSend < nPeriodicSend; iSend++) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + iPeriodic = config->GetMarker_All_PerBound(iMarker); + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Get the current periodic point index. We only communicate + the owned nodes on a rank, as the MPI comms will take care of + the halos after completing the periodic comms. ---*/ + + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + if (geometry->node[iPoint]->GetDomain()) { + + /*--- Get the rank that holds the matching periodic point + on the other marker in the periodic pair. ---*/ + + iRank = (int)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 + index on the matching periodic point and the periodic marker + index to be communicated to the recv rank. ---*/ + + if (iRank == Neighbors_PeriodicSend[iSend]) { + Local_Point_PeriodicSend[ii] = iPoint; + Local_Marker_PeriodicSend[ii] = (unsigned long)iMarker; + jj = ii*nPackets; + idSend[jj] = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); + jj++; + idSend[jj] = (unsigned long)iPeriodic; + ii++; + } + + } + } + } + } + } + + /*--- Allocate arrays for receiving the periodic point index and marker + index to the recv rank so that it can store the local values. ---*/ + + unsigned long *idRecv = new unsigned long[nPoint_PeriodicRecv[nPeriodicRecv]*nPackets]; + for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]*nPackets; iRecv++) + idRecv[iRecv] = 0; + +#ifdef HAVE_MPI + + int iMessage, offset, count, source, dest, tag; + + /*--- Launch the non-blocking recv's first. Note that we have stored + the counts and sources, so we can launch these before we even load + the data and send from the periodically matching ranks. ---*/ + + iMessage = 0; + for (iRecv = 0; iRecv < nPeriodicRecv; iRecv++) { + + /*--- Compute our location in the recv buffer. ---*/ + + offset = nPackets*nPoint_PeriodicRecv[iRecv]; + + /*--- Take advantage of cumulative storage format to get the number + of elems that we need to recv. ---*/ + + count = nPackets*(nPoint_PeriodicRecv[iRecv+1] - nPoint_PeriodicRecv[iRecv]); + + /*--- Get the rank from which we receive the message. ---*/ + + source = Neighbors_PeriodicRecv[iRecv]; + tag = source + 1; + + /*--- Post non-blocking recv for this proc. ---*/ + + SU2_MPI::Irecv(&(static_cast(idRecv)[offset]), + count, MPI_UNSIGNED_LONG, source, tag, MPI_COMM_WORLD, + &(req_PeriodicRecv[iMessage])); + + /*--- Increment message counter. ---*/ + + iMessage++; + + } + + /*--- Post the non-blocking sends. ---*/ + + iMessage = 0; + for (iSend = 0; iSend < nPeriodicSend; iSend++) { + + /*--- Compute our location in the send buffer. ---*/ + + offset = nPackets*nPoint_PeriodicSend[iSend]; + + /*--- Take advantage of cumulative storage format to get the number + of points that we need to send. ---*/ + + count = nPackets*(nPoint_PeriodicSend[iSend+1] - nPoint_PeriodicSend[iSend]); + + /*--- Get the rank to which we send the message. ---*/ + + dest = Neighbors_PeriodicSend[iSend]; + tag = rank + 1; + + /*--- Post non-blocking send for this proc. ---*/ + + SU2_MPI::Isend(&(static_cast(idSend)[offset]), + count, MPI_UNSIGNED_LONG, dest, tag, MPI_COMM_WORLD, + &(req_PeriodicSend[iMessage])); + + /*--- Increment message counter. ---*/ + + iMessage++; + + } + + /*--- Wait for the non-blocking comms to complete. ---*/ + + SU2_MPI::Waitall(nPeriodicSend, req_PeriodicSend, MPI_STATUS_IGNORE); + SU2_MPI::Waitall(nPeriodicRecv, req_PeriodicRecv, MPI_STATUS_IGNORE); + +#else + + /*--- Copy my own rank's data into the recv buffer directly in serial. ---*/ + + int myStart, myFinal; + for (int val_iSend = 0; val_iSend < nPeriodicSend; val_iSend++) { + iRank = geometry->PeriodicRecv2Neighbor[rank]; + iRecv = geometry->nPoint_PeriodicRecv[iRank]*nPackets; + myStart = nPoint_PeriodicSend[val_iSend]*nPackets; + myFinal = nPoint_PeriodicSend[val_iSend+1]*nPackets; + for (iSend = myStart; iSend < myFinal; iSend++) { + idRecv[iRecv] = idSend[iSend]; + iRecv++; + } + } + +#endif + + /*--- Store the local periodic point and marker index values in our + data structures so we can quickly unpack data during the iterations. ---*/ + + ii = 0; + for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]; iRecv++) { + Local_Point_PeriodicRecv[iRecv] = idRecv[ii]; ii++; + Local_Marker_PeriodicRecv[iRecv] = idRecv[ii]; ii++; + } + + delete [] idSend; + delete [] idRecv; + +} + +void CGeometry::AllocatePeriodicComms(unsigned short val_countPerPeriodicPoint) { + + /*--- This routine is activated whenever we attempt to perform + a periodic MPI communication with our neighbors but the + memory buffer allocated is not large enough for the packet size. + Therefore, we deallocate the previously allocated arrays and + reallocate a large enough array. Note that after the first set + communications, this routine will not need to be called again. ---*/ + + int iSend, iRecv, nSend, nRecv; + + /*--- Store the larger packet size to the class data. ---*/ + + countPerPeriodicPoint = val_countPerPeriodicPoint; + + /*--- Store the total size of the send/recv arrays for clarity. ---*/ + + nSend = countPerPeriodicPoint*nPoint_PeriodicSend[nPeriodicSend]; + nRecv = countPerPeriodicPoint*nPoint_PeriodicRecv[nPeriodicRecv]; + + /*-- Deallocate and reallocate our cummunication memory. ---*/ + + if (bufD_PeriodicSend != NULL) delete [] bufD_PeriodicSend; + + bufD_PeriodicSend = new su2double[nSend]; + for (iSend = 0; iSend < nSend; iSend++) + bufD_PeriodicSend[iSend] = 0.0; + + if (bufD_PeriodicRecv != NULL) delete [] bufD_PeriodicRecv; + + bufD_PeriodicRecv = new su2double[nRecv]; + for (iRecv = 0; iRecv < nRecv; iRecv++) + bufD_PeriodicRecv[iRecv] = 0.0; + + if (bufS_PeriodicSend != NULL) delete [] bufS_PeriodicSend; + + bufS_PeriodicSend = new unsigned short[nSend]; + for (iSend = 0; iSend < nSend; iSend++) + bufS_PeriodicSend[iSend] = 0; + + if (bufS_PeriodicRecv != NULL) delete [] bufS_PeriodicRecv; + + bufS_PeriodicRecv = new unsigned short[nRecv]; + for (iRecv = 0; iRecv < nRecv; iRecv++) + bufS_PeriodicRecv[iRecv] = 0; + +} + +void CGeometry::PostPeriodicRecvs(CGeometry *geometry, + CConfig *config, + unsigned short commType) { + + /*--- In parallel, communicate the data with non-blocking send/recv. ---*/ + +#ifdef HAVE_MPI + + /*--- Local variables ---*/ + + int iMessage, iRecv, offset, nPointPeriodic, count, source, tag; + + /*--- Launch the non-blocking recv's first. Note that we have stored + the counts and sources, so we can launch these before we even load + the data and send from the neighbor ranks. ---*/ + + iMessage = 0; + for (iRecv = 0; iRecv < nPeriodicRecv; iRecv++) { + + /*--- Compute our location in the recv buffer. ---*/ + + offset = countPerPeriodicPoint*nPoint_PeriodicRecv[iRecv]; + + /*--- Take advantage of cumulative storage format to get the number + of elems that we need to recv. ---*/ + + nPointPeriodic = nPoint_PeriodicRecv[iRecv+1] - nPoint_PeriodicRecv[iRecv]; + + /*--- Total count can include multiple pieces of data per element. ---*/ + + count = countPerPeriodicPoint*nPointPeriodic; + + /*--- Get the rank from which we receive the message. ---*/ + + source = Neighbors_PeriodicRecv[iRecv]; + tag = source + 1; + + /*--- Post non-blocking recv for this proc. ---*/ + + switch (commType) { + case COMM_TYPE_DOUBLE: + SU2_MPI::Irecv(&(static_cast(bufD_PeriodicRecv)[offset]), + count, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, + &(req_PeriodicRecv[iMessage])); + break; + case COMM_TYPE_UNSIGNED_SHORT: + SU2_MPI::Irecv(&(static_cast(bufS_PeriodicRecv)[offset]), + count, MPI_UNSIGNED_SHORT, source, tag, MPI_COMM_WORLD, + &(req_PeriodicRecv[iMessage])); + break; + default: + SU2_MPI::Error("Unrecognized data type for periodic MPI comms.", + CURRENT_FUNCTION); + break; + } + + /*--- Increment message counter. ---*/ + + iMessage++; + + } + +#endif + +} + +void CGeometry::PostPeriodicSends(CGeometry *geometry, + CConfig *config, + unsigned short commType, + int val_iSend) { + + /*--- In parallel, communicate the data with non-blocking send/recv. ---*/ + +#ifdef HAVE_MPI + + /*--- Local variables ---*/ + + int iMessage, offset, nPointPeriodic, count, dest, tag; + + /*--- Post the non-blocking send as soon as the buffer is loaded. ---*/ + + iMessage = val_iSend; + + /*--- Compute our location in the send buffer. ---*/ + + offset = countPerPeriodicPoint*nPoint_PeriodicSend[val_iSend]; + + /*--- Take advantage of cumulative storage format to get the number + of points that we need to send. ---*/ + + nPointPeriodic = (nPoint_PeriodicSend[val_iSend+1] - + nPoint_PeriodicSend[val_iSend]); + + /*--- Total count can include multiple pieces of data per element. ---*/ + + count = countPerPeriodicPoint*nPointPeriodic; + + /*--- Get the rank to which we send the message. ---*/ + + dest = Neighbors_PeriodicSend[val_iSend]; + tag = rank + 1; + + /*--- Post non-blocking send for this proc. ---*/ + + switch (commType) { + case COMM_TYPE_DOUBLE: + SU2_MPI::Isend(&(static_cast(bufD_PeriodicSend)[offset]), + count, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD, + &(req_PeriodicSend[iMessage])); + break; + case COMM_TYPE_UNSIGNED_SHORT: + SU2_MPI::Isend(&(static_cast(bufS_PeriodicSend)[offset]), + count, MPI_UNSIGNED_SHORT, dest, tag, MPI_COMM_WORLD, + &(req_PeriodicSend[iMessage])); + break; + default: + SU2_MPI::Error("Unrecognized data type for periodic MPI comms.", + CURRENT_FUNCTION); + break; + } + +#else + + /*--- Copy my own rank's data into the recv buffer directly in serial. ---*/ + + int iSend, myStart, myFinal, iRecv, iRank; + iRank = geometry->PeriodicRecv2Neighbor[rank]; + iRecv = geometry->nPoint_PeriodicRecv[iRank]*countPerPeriodicPoint; + myStart = nPoint_PeriodicSend[val_iSend]*countPerPeriodicPoint; + myFinal = nPoint_PeriodicSend[val_iSend+1]*countPerPeriodicPoint; + for (iSend = myStart; iSend < myFinal; iSend++) { + switch (commType) { + case COMM_TYPE_DOUBLE: + bufD_PeriodicRecv[iRecv] = bufD_PeriodicSend[iSend]; + break; + case COMM_TYPE_UNSIGNED_SHORT: + bufS_PeriodicRecv[iRecv] = bufS_PeriodicSend[iSend]; + break; + default: + SU2_MPI::Error("Unrecognized data type for periodic MPI comms.", + CURRENT_FUNCTION); + break; + } + iRecv++; + } + +#endif + +} + +su2double CGeometry::Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord) { + su2double CrossProduct[3], iVector[3], jVector[3], distance, modulus; + unsigned short iDim; + + for (iDim = 0; iDim < 3; iDim ++) { + iVector[iDim] = jCoord[iDim] - iCoord[iDim]; + jVector[iDim] = kCoord[iDim] - iCoord[iDim]; + } + + CrossProduct[0] = iVector[1]*jVector[2] - iVector[2]*jVector[1]; + CrossProduct[1] = iVector[2]*jVector[0] - iVector[0]*jVector[2]; + CrossProduct[2] = iVector[0]*jVector[1] - iVector[1]*jVector[0]; + + modulus = sqrt(CrossProduct[0]*CrossProduct[0]+CrossProduct[1]*CrossProduct[1]+CrossProduct[2]*CrossProduct[2]); + + distance = 0.0; + for (iDim = 0; iDim < 3; iDim ++) + distance += CrossProduct[iDim]*(Coord[iDim]-iCoord[iDim]); + distance /= modulus; + + return distance; + +} + +long CGeometry::FindEdge(unsigned long first_point, unsigned long second_point) { + unsigned long iPoint = 0; + unsigned short iNode; + for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { + iPoint = node[first_point]->GetPoint(iNode); + if (iPoint == second_point) break; + } + + if (iPoint == second_point) return node[first_point]->GetEdge(iNode); + else { + char buf[100]; + SPRINTF(buf, "Can't find the edge that connects %lu and %lu.", first_point, second_point); + SU2_MPI::Error(buf, CURRENT_FUNCTION); + return 0; + } +} + +bool CGeometry::CheckEdge(unsigned long first_point, unsigned long second_point) { + unsigned long iPoint = 0; + unsigned short iNode; + for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { + iPoint = node[first_point]->GetPoint(iNode); + if (iPoint == second_point) break; + } + + if (iPoint == second_point) return true; + else return false; + +} + +void CGeometry::SetEdges(void) { + unsigned long iPoint, jPoint; + long iEdge; + unsigned short jNode, iNode; + long TestEdge = 0; + + nEdge = 0; + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + jPoint = node[iPoint]->GetPoint(iNode); + for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) + if (node[jPoint]->GetPoint(jNode) == iPoint) { + TestEdge = node[jPoint]->GetEdge(jNode); + break; + } + if (TestEdge == -1) { + node[iPoint]->SetEdge(nEdge, iNode); + node[jPoint]->SetEdge(nEdge, jNode); + nEdge++; + } + } + + edge = new CEdge*[nEdge]; + + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + jPoint = node[iPoint]->GetPoint(iNode); + iEdge = FindEdge(iPoint, jPoint); + if (iPoint < jPoint) edge[iEdge] = new CEdge(iPoint, jPoint, nDim); + } +} + +void CGeometry::SetFaces(void) { + // unsigned long iPoint, jPoint, iFace; + // unsigned short jNode, iNode; + // long TestFace = 0; + // + // nFace = 0; + // for (iPoint = 0; iPoint < nPoint; iPoint++) + // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + // jPoint = node[iPoint]->GetPoint(iNode); + // for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) + // if (node[jPoint]->GetPoint(jNode) == iPoint) { + // TestFace = node[jPoint]->GetFace(jNode); + // break; + // } + // if (TestFace == -1) { + // node[iPoint]->SetFace(nFace, iNode); + // node[jPoint]->SetFace(nFace, jNode); + // nFace++; + // } + // } + // + // face = new CFace*[nFace]; + // + // for (iPoint = 0; iPoint < nPoint; iPoint++) + // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { + // jPoint = node[iPoint]->GetPoint(iNode); + // iFace = FindFace(iPoint, jPoint); + // if (iPoint < jPoint) face[iFace] = new CFace(iPoint, jPoint, nDim); + // } +} + +void CGeometry::TestGeometry(void) { + + ofstream para_file; + + para_file.open("test_geometry.dat", ios::out); + + su2double *Normal = new su2double[nDim]; + + for (unsigned long iEdge = 0; iEdge < nEdge; iEdge++) { + para_file << "Edge index: " << iEdge << endl; + para_file << " Point index: " << edge[iEdge]->GetNode(0) << "\t" << edge[iEdge]->GetNode(1) << endl; + edge[iEdge]->GetNormal(Normal); + para_file << " Face normal : "; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + para_file << Normal[iDim] << "\t"; + para_file << endl; + } + + para_file << endl; + para_file << endl; + para_file << endl; + para_file << endl; + + for (unsigned short iMarker =0; iMarker < nMarker; iMarker++) { + para_file << "Marker index: " << iMarker << endl; + for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + para_file << " Vertex index: " << iVertex << endl; + para_file << " Point index: " << vertex[iMarker][iVertex]->GetNode() << endl; + para_file << " Point coordinates : "; + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + para_file << node[vertex[iMarker][iVertex]->GetNode()]->GetCoord(iDim) << "\t";} + para_file << endl; + vertex[iMarker][iVertex]->GetNormal(Normal); + para_file << " Face normal : "; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + para_file << Normal[iDim] << "\t"; + para_file << endl; + } + } + + delete [] Normal; + +} + +void CGeometry::SetSpline(vector &x, vector &y, unsigned long n, su2double yp1, su2double ypn, vector &y2) { + unsigned long i, k; + su2double p, qn, sig, un, *u; + + u = new su2double [n]; + + if (yp1 > 0.99e30) // The lower boundary condition is set either to be "nat + y2[0]=u[0]=0.0; // -ural" + else { // or else to have a specified first derivative. + y2[0] = -0.5; + u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yp1); + } + + for (i=2; i<=n-1; i++) { // This is the decomposition loop of the tridiagonal al- + sig=(x[i-1]-x[i-2])/(x[i]-x[i-2]); // gorithm. y2 and u are used for tem- + p=sig*y2[i-2]+2.0; // porary storage of the decomposed + y2[i-1]=(sig-1.0)/p; // factors. + + su2double a1 = (y[i]-y[i-1])/(x[i]-x[i-1]); if (x[i] == x[i-1]) a1 = 1.0; + su2double a2 = (y[i-1]-y[i-2])/(x[i-1]-x[i-2]); if (x[i-1] == x[i-2]) a2 = 1.0; + u[i-1]= a1 - a2; + u[i-1]=(6.0*u[i-1]/(x[i]-x[i-2])-sig*u[i-2])/p; + + } + + if (ypn > 0.99e30) // The upper boundary condition is set either to be + qn=un=0.0; // "natural" + else { // or else to have a specified first derivative. + qn=0.5; + un=(3.0/(x[n-1]-x[n-2]))*(ypn-(y[n-1]-y[n-2])/(x[n-1]-x[n-2])); + } + y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0); + for (k=n-1; k>=1; k--) // This is the backsubstitution loop of the tridiagonal + y2[k-1]=y2[k-1]*y2[k]+u[k-1]; // algorithm. + + delete[] u; + +} + +su2double CGeometry::GetSpline(vector&xa, vector&ya, vector&y2a, unsigned long n, su2double x) { + unsigned long klo, khi, k; + su2double h, b, a, y; + + if (x < xa[0]) x = xa[0]; // Clip max and min values + if (x > xa[n-1]) x = xa[n-1]; + + klo = 1; // We will find the right place in the table by means of + khi = n; // bisection. This is optimal if sequential calls to this + while (khi-klo > 1) { // routine are at random values of x. If sequential calls + k = (khi+klo) >> 1; // are in order, and closely spaced, one would do better + if (xa[k-1] > x) khi = k; // to store previous values of klo and khi and test if + else klo=k; // they remain appropriate on the next call. + } // klo and khi now bracket the input value of x + h = xa[khi-1] - xa[klo-1]; + if (h == 0.0) h = EPS; // cout << "Bad xa input to routine splint" << endl; // The xa?s must be distinct. + a = (xa[khi-1]-x)/h; + b = (x-xa[klo-1])/h; // Cubic spline polynomial is now evaluated. + y = a*ya[klo-1]+b*ya[khi-1]+((a*a*a-a)*y2a[klo-1]+(b*b*b-b)*y2a[khi-1])*(h*h)/6.0; + + return y; +} + +bool CGeometry::SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, + su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp) { + su2double u[3], v[3], Denominator, Numerator, Aux, ModU; + su2double epsilon = 1E-6; // An epsilon is added to eliminate, as much as possible, the posibility of a line that intersects a point + unsigned short iDim; + + for (iDim = 0; iDim < 3; iDim++) { + u[iDim] = Segment_P1[iDim] - Segment_P0[iDim]; + v[iDim] = (Plane_P0[iDim]+epsilon) - Segment_P0[iDim]; + } + + ModU = sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2]); + + Numerator = (Plane_Normal[0]+epsilon)*v[0] + (Plane_Normal[1]+epsilon)*v[1] + (Plane_Normal[2]+epsilon)*v[2]; + Denominator = (Plane_Normal[0]+epsilon)*u[0] + (Plane_Normal[1]+epsilon)*u[1] + (Plane_Normal[2]+epsilon)*u[2]; + + if (fabs(Denominator) <= 0.0) return (false); // No intersection. + + Aux = Numerator / Denominator; + + if (Aux < 0.0 || Aux > 1.0) return (false); // No intersection. + + for (iDim = 0; iDim < 3; iDim++) + Intersection[iDim] = Segment_P0[iDim] + Aux * u[iDim]; + + + /*--- Check that the intersection is in the segment ---*/ + + for (iDim = 0; iDim < 3; iDim++) { + u[iDim] = Segment_P0[iDim] - Intersection[iDim]; + v[iDim] = Segment_P1[iDim] - Intersection[iDim]; + } + + Variable_Interp = Variable_P0 + (Variable_P1 - Variable_P0)*sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2])/ModU; + + Denominator = (Plane_Normal[0]+epsilon)*u[0] + (Plane_Normal[1]+epsilon)*u[1] + (Plane_Normal[2]+epsilon)*u[2]; + Numerator = (Plane_Normal[0]+epsilon)*v[0] + (Plane_Normal[1]+epsilon)*v[1] + (Plane_Normal[2]+epsilon)*v[2]; + + Aux = Numerator * Denominator; + + if (Aux > 0.0) return (false); // Intersection outside the segment. + + return (true); + +} + +bool CGeometry::RayIntersectsTriangle(su2double orig[3], su2double dir[3], + su2double vert0[3], su2double vert1[3], su2double vert2[3], + su2double *intersect) { + + const passivedouble epsilon = 0.000001; + su2double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; + su2double det, inv_det, t, u, v; + + /*--- Find vectors for two edges sharing vert0 ---*/ + + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + + /*--- Begin calculating determinant - also used to calculate U parameter ---*/ + + CROSS(pvec, dir, edge2); + + /*--- If determinant is near zero, ray lies in plane of triangle ---*/ + + det = DOT(edge1, pvec); + + + if (fabs(det) < epsilon) return(false); + + inv_det = 1.0 / det; + + /*--- Calculate distance from vert0 to ray origin ---*/ + + SUB(tvec, orig, vert0); + + /*--- Calculate U parameter and test bounds ---*/ + + u = inv_det * DOT(tvec, pvec); + + if (u < 0.0 || u > 1.0) return(false); + + /*--- prepare to test V parameter ---*/ + + CROSS(qvec, tvec, edge1); + + /*--- Calculate V parameter and test bounds ---*/ + + v = inv_det * DOT(dir, qvec); + + if (v < 0.0 || u + v > 1.0) return(false); + + /*--- Calculate t, ray intersects triangle ---*/ + + t = inv_det * DOT(edge2, qvec); + + /*--- Compute the intersection point in cartesian coordinates ---*/ + + intersect[0] = orig[0] + (t * dir[0]); + intersect[1] = orig[1] + (t * dir[1]); + intersect[2] = orig[2] + (t * dir[2]); + + return (true); + +} + +bool CGeometry::SegmentIntersectsLine(su2double point0[2], su2double point1[2], su2double vert0[2], su2double vert1[2]) { + + su2double det, diff0_A, diff0_B, diff1_A, diff1_B, intersect[2]; + + diff0_A = point0[0] - point1[0]; + diff1_A = point0[1] - point1[1]; + + diff0_B = vert0[0] - vert1[0]; + diff1_B = vert0[1] - vert1[1]; + + det = (diff0_A)*(diff1_B) - (diff1_A)*(diff0_B); + + if (det == 0) return false; + + /*--- Compute point of intersection ---*/ + + intersect[0] = ((point0[0]*point1[1] - point0[1]*point1[0])*diff0_B + -(vert0[0]* vert1[1] - vert0[1]* vert1[0])*diff0_A)/det; + + intersect[1] = ((point0[0]*point1[1] - point0[1]*point1[0])*diff1_B + -(vert0[0]* vert1[1] - vert0[1]* vert1[0])*diff1_A)/det; + + + /*--- Check that the point is between the two surface points ---*/ + + su2double dist0, dist1, length; + + dist0 = (intersect[0] - point0[0])*(intersect[0] - point0[0]) + +(intersect[1] - point0[1])*(intersect[1] - point0[1]); + + dist1 = (intersect[0] - point1[0])*(intersect[0] - point1[0]) + +(intersect[1] - point1[1])*(intersect[1] - point1[1]); + + length = diff0_A*diff0_A + +diff1_A*diff1_A; + + if ( (dist0 > length) || (dist1 > length) ) { + return false; + } + + return true; +} + +bool CGeometry::SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], + su2double vert0[3], su2double vert1[3], su2double vert2[3]) { + + su2double dir[3], intersect[3], u[3], v[3], edge1[3], edge2[3], Plane_Normal[3], Denominator, Numerator, Aux; + + SUB(dir, point1, point0); + + if (RayIntersectsTriangle(point0, dir, vert0, vert1, vert2, intersect)) { + + /*--- Check that the intersection is in the segment ---*/ + + SUB(u, point0, intersect); + SUB(v, point1, intersect); + + SUB(edge1, vert1, vert0); + SUB(edge2, vert2, vert0); + CROSS(Plane_Normal, edge1, edge2); + + Denominator = DOT(Plane_Normal, u); + Numerator = DOT(Plane_Normal, v); + + Aux = Numerator * Denominator; + + /*--- Intersection outside the segment ---*/ + + if (Aux > 0.0) return (false); + + } + else { + + /*--- No intersection with the ray ---*/ + + return (false); + + } + + /*--- Intersection inside the segment ---*/ + + return (true); + +} + +void CGeometry::ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, + su2double MinXCoord, su2double MaxXCoord, + su2double MinYCoord, su2double MaxYCoord, + su2double MinZCoord, su2double MaxZCoord, + su2double *FlowVariable, + vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, + vector &Zcoord_Airfoil, vector &Variable_Airfoil, + bool original_surface, CConfig *config) { + + AD_BEGIN_PASSIVE + + unsigned short iMarker, iNode, jNode, iDim, Index = 0; + bool intersect; + long Next_Edge = 0; + unsigned long iPoint, jPoint, iElem, Trailing_Point, Airfoil_Point, iVertex, iEdge, PointIndex, jEdge; + su2double Segment_P0[3] = {0.0, 0.0, 0.0}, Segment_P1[3] = {0.0, 0.0, 0.0}, Variable_P0 = 0.0, Variable_P1 = 0.0, Intersection[3] = {0.0, 0.0, 0.0}, Trailing_Coord, + *VarCoord = NULL, Variable_Interp, v1[3] = {0.0, 0.0, 0.0}, v3[3] = {0.0, 0.0, 0.0}, CrossProduct = 1.0; + bool Found_Edge; + passivedouble Dist_Value; + vector Xcoord_Index0, Ycoord_Index0, Zcoord_Index0, Variable_Index0, Xcoord_Index1, Ycoord_Index1, Zcoord_Index1, Variable_Index1; + vector IGlobalID_Index0, JGlobalID_Index0, IGlobalID_Index1, JGlobalID_Index1, IGlobalID_Airfoil, JGlobalID_Airfoil; + vector Conection_Index0, Conection_Index1; + vector Duplicate; + vector::iterator it; + su2double **Coord_Variation = NULL; + vector XcoordExtra, YcoordExtra, ZcoordExtra, VariableExtra; + vector IGlobalIDExtra, JGlobalIDExtra; + vector AddExtra; + unsigned long EdgeDonor; + bool FoundEdge; + +#ifdef HAVE_MPI + unsigned long nLocalEdge, MaxLocalEdge, *Buffer_Send_nEdge, *Buffer_Receive_nEdge, nBuffer_Coord, nBuffer_Variable, nBuffer_GlobalID; + int nProcessor, iProcessor; + su2double *Buffer_Send_Coord, *Buffer_Receive_Coord; + su2double *Buffer_Send_Variable, *Buffer_Receive_Variable; + unsigned long *Buffer_Send_GlobalID, *Buffer_Receive_GlobalID; +#endif + + Xcoord_Airfoil.clear(); + Ycoord_Airfoil.clear(); + Zcoord_Airfoil.clear(); + Variable_Airfoil.clear(); + IGlobalID_Airfoil.clear(); + JGlobalID_Airfoil.clear(); + + /*--- Set the right plane in 2D (note the change in Y-Z plane) ---*/ + + if (nDim == 2) { + Plane_P0[0] = 0.0; Plane_P0[1] = 0.0; Plane_P0[2] = 0.0; + Plane_Normal[0] = 0.0; Plane_Normal[1] = 1.0; Plane_Normal[2] = 0.0; + } + + /*--- Grid movement is stored using a vertices information, + we should go from vertex to points ---*/ + + if (original_surface == false) { + + Coord_Variation = new su2double *[nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) + Coord_Variation[iPoint] = new su2double [nDim]; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_GeoEval(iMarker) == YES) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + VarCoord = vertex[iMarker][iVertex]->GetVarCoord(); + iPoint = vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) + Coord_Variation[iPoint][iDim] = VarCoord[iDim]; + } + } + } + + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_GeoEval(iMarker) == YES) { + + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { + + PointIndex=0; + + /*--- To decide if an element is going to be used or not should be done element based, + The first step is to compute and average coordinate for the element ---*/ + + su2double AveXCoord = 0.0; + su2double AveYCoord = 0.0; + su2double AveZCoord = 0.0; + + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + AveXCoord += node[iPoint]->GetCoord(0); + AveYCoord += node[iPoint]->GetCoord(1); + if (nDim == 3) AveZCoord += node[iPoint]->GetCoord(2); + } + + AveXCoord /= su2double(bound[iMarker][iElem]->GetnNodes()); + AveYCoord /= su2double(bound[iMarker][iElem]->GetnNodes()); + AveZCoord /= su2double(bound[iMarker][iElem]->GetnNodes()); + + /*--- To only cut one part of the nacelle based on the cross product + of the normal to the plane and a vector that connect the point + with the center line ---*/ + + CrossProduct = 1.0; + + if (config->GetGeo_Description() == NACELLE) { + + su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180; + su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180; + + /*--- Translate to the origin ---*/ + + su2double XCoord_Trans = AveXCoord - config->GetNacelleLocation(0); + su2double YCoord_Trans = AveYCoord - config->GetNacelleLocation(1); + su2double ZCoord_Trans = AveZCoord - config->GetNacelleLocation(2); + + /*--- Apply tilt angle ---*/ + + su2double XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle); + su2double YCoord_Trans_Tilt = YCoord_Trans; + su2double ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle); + + /*--- Apply toe angle ---*/ + + su2double YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle); + su2double ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt; + + /*--- Undo plane rotation, we have already rotated the nacelle ---*/ + + /*--- Undo tilt angle ---*/ + + su2double XPlane_Normal_Tilt = Plane_Normal[0]*cos(-Tilt_Angle) + Plane_Normal[2]*sin(-Tilt_Angle); + su2double YPlane_Normal_Tilt = Plane_Normal[1]; + su2double ZPlane_Normal_Tilt = Plane_Normal[2]*cos(-Tilt_Angle) - Plane_Normal[0]*sin(-Tilt_Angle); + + /*--- Undo toe angle ---*/ + + su2double YPlane_Normal_Tilt_Toe = XPlane_Normal_Tilt*sin(-Toe_Angle) + YPlane_Normal_Tilt*cos(-Toe_Angle); + su2double ZPlane_Normal_Tilt_Toe = ZPlane_Normal_Tilt; + + + v1[1] = YCoord_Trans_Tilt_Toe - 0.0; + v1[2] = ZCoord_Trans_Tilt_Toe - 0.0; + v3[0] = v1[1]*ZPlane_Normal_Tilt_Toe-v1[2]*YPlane_Normal_Tilt_Toe; + CrossProduct = v3[0] * 1.0; + + } + + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem]->GetNode(iNode); + + for (jNode = 0; jNode < bound[iMarker][iElem]->GetnNodes(); jNode++) { + jPoint = bound[iMarker][iElem]->GetNode(jNode); + + /*--- CrossProduct concept is delicated because it allows triangles where only one side is divided by a plane. + that is going against the concept that all the triangles are divided twice and causes probelms because + Xcoord_Index0.size() > Xcoord_Index1.size()! ---*/ + + if ((jPoint > iPoint) && (CrossProduct >= 0.0) + && ((AveXCoord > MinXCoord) && (AveXCoord < MaxXCoord)) + && ((AveYCoord > MinYCoord) && (AveYCoord < MaxYCoord)) + && ((AveZCoord > MinZCoord) && (AveZCoord < MaxZCoord))) { + + Segment_P0[0] = 0.0; Segment_P0[1] = 0.0; Segment_P0[2] = 0.0; Variable_P0 = 0.0; + Segment_P1[0] = 0.0; Segment_P1[1] = 0.0; Segment_P1[2] = 0.0; Variable_P1 = 0.0; + + + for (iDim = 0; iDim < nDim; iDim++) { + if (original_surface == true) { + Segment_P0[iDim] = node[iPoint]->GetCoord(iDim); + Segment_P1[iDim] = node[jPoint]->GetCoord(iDim); + } + else { + Segment_P0[iDim] = node[iPoint]->GetCoord(iDim) + Coord_Variation[iPoint][iDim]; + Segment_P1[iDim] = node[jPoint]->GetCoord(iDim) + Coord_Variation[jPoint][iDim]; + } + } + + if (FlowVariable != NULL) { + Variable_P0 = FlowVariable[iPoint]; + Variable_P1 = FlowVariable[jPoint]; + } + + /*--- In 2D add the points directly (note the change between Y and Z coordinate) ---*/ + + if (nDim == 2) { + Xcoord_Index0.push_back(Segment_P0[0]); Xcoord_Index1.push_back(Segment_P1[0]); + Ycoord_Index0.push_back(Segment_P0[2]); Ycoord_Index1.push_back(Segment_P1[2]); + Zcoord_Index0.push_back(Segment_P0[1]); Zcoord_Index1.push_back(Segment_P1[1]); + Variable_Index0.push_back(Variable_P0); Variable_Index1.push_back(Variable_P1); + IGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); IGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex()); + JGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); JGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex()); + PointIndex++; + } + + /*--- In 3D compute the intersection ---*/ + + else if (nDim == 3) { + intersect = SegmentIntersectsPlane(Segment_P0, Segment_P1, Variable_P0, Variable_P1, Plane_P0, Plane_Normal, Intersection, Variable_Interp); + if (intersect == true) { + if (PointIndex == 0) { + Xcoord_Index0.push_back(Intersection[0]); + Ycoord_Index0.push_back(Intersection[1]); + Zcoord_Index0.push_back(Intersection[2]); + Variable_Index0.push_back(Variable_Interp); + IGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); + JGlobalID_Index0.push_back(node[jPoint]->GetGlobalIndex()); + } + if (PointIndex == 1) { + Xcoord_Index1.push_back(Intersection[0]); + Ycoord_Index1.push_back(Intersection[1]); + Zcoord_Index1.push_back(Intersection[2]); + Variable_Index1.push_back(Variable_Interp); + IGlobalID_Index1.push_back(node[iPoint]->GetGlobalIndex()); + JGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex()); + } + PointIndex++; + } + } + + } + } + } + + } + } + } + + if (original_surface == false) { + for (iPoint = 0; iPoint < nPoint; iPoint++) + delete [] Coord_Variation[iPoint]; + delete [] Coord_Variation; + } + +#ifdef HAVE_MPI + + /*--- Copy the coordinates of all the points in the plane to the master node ---*/ + + nLocalEdge = 0, MaxLocalEdge = 0; + nProcessor = size; + + Buffer_Send_nEdge = new unsigned long [1]; + Buffer_Receive_nEdge = new unsigned long [nProcessor]; + + nLocalEdge = Xcoord_Index0.size(); + + Buffer_Send_nEdge[0] = nLocalEdge; + + SU2_MPI::Allreduce(&nLocalEdge, &MaxLocalEdge, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nEdge, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nEdge, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + Buffer_Send_Coord = new su2double [MaxLocalEdge*6]; + Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalEdge*6]; + + Buffer_Send_Variable = new su2double [MaxLocalEdge*2]; + Buffer_Receive_Variable = new su2double [nProcessor*MaxLocalEdge*2]; + + Buffer_Send_GlobalID = new unsigned long [MaxLocalEdge*4]; + Buffer_Receive_GlobalID = new unsigned long [nProcessor*MaxLocalEdge*4]; + + nBuffer_Coord = MaxLocalEdge*6; + nBuffer_Variable = MaxLocalEdge*2; + nBuffer_GlobalID = MaxLocalEdge*4; + + for (iEdge = 0; iEdge < nLocalEdge; iEdge++) { + Buffer_Send_Coord[iEdge*6 + 0] = Xcoord_Index0[iEdge]; + Buffer_Send_Coord[iEdge*6 + 1] = Ycoord_Index0[iEdge]; + Buffer_Send_Coord[iEdge*6 + 2] = Zcoord_Index0[iEdge]; + Buffer_Send_Coord[iEdge*6 + 3] = Xcoord_Index1[iEdge]; + Buffer_Send_Coord[iEdge*6 + 4] = Ycoord_Index1[iEdge]; + Buffer_Send_Coord[iEdge*6 + 5] = Zcoord_Index1[iEdge]; + + Buffer_Send_Variable[iEdge*2 + 0] = Variable_Index0[iEdge]; + Buffer_Send_Variable[iEdge*2 + 1] = Variable_Index1[iEdge]; + + Buffer_Send_GlobalID[iEdge*4 + 0] = IGlobalID_Index0[iEdge]; + Buffer_Send_GlobalID[iEdge*4 + 1] = JGlobalID_Index0[iEdge]; + Buffer_Send_GlobalID[iEdge*4 + 2] = IGlobalID_Index1[iEdge]; + Buffer_Send_GlobalID[iEdge*4 + 3] = JGlobalID_Index1[iEdge]; + } + + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_Variable, nBuffer_Variable, MPI_DOUBLE, Buffer_Receive_Variable, nBuffer_Variable, MPI_DOUBLE, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_GlobalID, nBuffer_GlobalID, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalID, nBuffer_GlobalID, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); + + /*--- Clean the vectors before adding the new vertices only to the master node ---*/ + + Xcoord_Index0.clear(); Xcoord_Index1.clear(); + Ycoord_Index0.clear(); Ycoord_Index1.clear(); + Zcoord_Index0.clear(); Zcoord_Index1.clear(); + Variable_Index0.clear(); Variable_Index1.clear(); + IGlobalID_Index0.clear(); IGlobalID_Index1.clear(); + JGlobalID_Index0.clear(); JGlobalID_Index1.clear(); + + /*--- Copy the boundary to the master node vectors ---*/ + + if (rank == MASTER_NODE) { + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iEdge = 0; iEdge < Buffer_Receive_nEdge[iProcessor]; iEdge++) { + Xcoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 0] ); + Ycoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 1] ); + Zcoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 2] ); + Xcoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 3] ); + Ycoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 4] ); + Zcoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 5] ); + + Variable_Index0.push_back( Buffer_Receive_Variable[ iProcessor*MaxLocalEdge*2 + iEdge*2 + 0] ); + Variable_Index1.push_back( Buffer_Receive_Variable[ iProcessor*MaxLocalEdge*2 + iEdge*2 + 1] ); + + IGlobalID_Index0.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 0] ); + JGlobalID_Index0.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 1] ); + IGlobalID_Index1.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 2] ); + JGlobalID_Index1.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 3] ); + + } + } + } + + delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; + delete[] Buffer_Send_Variable; delete[] Buffer_Receive_Variable; + delete[] Buffer_Send_GlobalID; delete[] Buffer_Receive_GlobalID; + delete[] Buffer_Send_nEdge; delete[] Buffer_Receive_nEdge; + +#endif + + if ((rank == MASTER_NODE) && (Xcoord_Index0.size() != 0)) { + + /*--- Remove singular edges ---*/ + + bool Remove; + + do { Remove = false; + for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { + + if (((IGlobalID_Index0[iEdge] == IGlobalID_Index1[iEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[iEdge])) || + ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[iEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[iEdge]))) { + + Xcoord_Index0.erase (Xcoord_Index0.begin() + iEdge); + Ycoord_Index0.erase (Ycoord_Index0.begin() + iEdge); + Zcoord_Index0.erase (Zcoord_Index0.begin() + iEdge); + Variable_Index0.erase (Variable_Index0.begin() + iEdge); + IGlobalID_Index0.erase (IGlobalID_Index0.begin() + iEdge); + JGlobalID_Index0.erase (JGlobalID_Index0.begin() + iEdge); + + Xcoord_Index1.erase (Xcoord_Index1.begin() + iEdge); + Ycoord_Index1.erase (Ycoord_Index1.begin() + iEdge); + Zcoord_Index1.erase (Zcoord_Index1.begin() + iEdge); + Variable_Index1.erase (Variable_Index1.begin() + iEdge); + IGlobalID_Index1.erase (IGlobalID_Index1.begin() + iEdge); + JGlobalID_Index1.erase (JGlobalID_Index1.begin() + iEdge); + + Remove = true; break; + } + if (Remove) break; + } + } while (Remove == true); + + /*--- Remove repeated edges computing distance, this could happend because the MPI ---*/ + + do { Remove = false; + for (iEdge = 0; iEdge < Xcoord_Index0.size()-1; iEdge++) { + for (jEdge = iEdge+1; jEdge < Xcoord_Index0.size(); jEdge++) { + + /*--- Edges with the same orientation ---*/ + + if ((((IGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge])) || + ((IGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]))) && + (((IGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge])) || + ((IGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge])))) { + + Xcoord_Index0.erase (Xcoord_Index0.begin() + jEdge); + Ycoord_Index0.erase (Ycoord_Index0.begin() + jEdge); + Zcoord_Index0.erase (Zcoord_Index0.begin() + jEdge); + Variable_Index0.erase (Variable_Index0.begin() + jEdge); + IGlobalID_Index0.erase (IGlobalID_Index0.begin() + jEdge); + JGlobalID_Index0.erase (JGlobalID_Index0.begin() + jEdge); + + Xcoord_Index1.erase (Xcoord_Index1.begin() + jEdge); + Ycoord_Index1.erase (Ycoord_Index1.begin() + jEdge); + Zcoord_Index1.erase (Zcoord_Index1.begin() + jEdge); + Variable_Index1.erase (Variable_Index1.begin() + jEdge); + IGlobalID_Index1.erase (IGlobalID_Index1.begin() + jEdge); + JGlobalID_Index1.erase (JGlobalID_Index1.begin() + jEdge); + + Remove = true; break; + + } + + /*--- Edges with oposite orientation ---*/ + + if ((((IGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge])) || + ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]))) && + (((IGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge])) || + ((IGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge])))) { + + Xcoord_Index0.erase (Xcoord_Index0.begin() + jEdge); + Ycoord_Index0.erase (Ycoord_Index0.begin() + jEdge); + Zcoord_Index0.erase (Zcoord_Index0.begin() + jEdge); + Variable_Index0.erase (Variable_Index0.begin() + jEdge); + IGlobalID_Index0.erase (IGlobalID_Index0.begin() + jEdge); + JGlobalID_Index0.erase (JGlobalID_Index0.begin() + jEdge); + + Xcoord_Index1.erase (Xcoord_Index1.begin() + jEdge); + Ycoord_Index1.erase (Ycoord_Index1.begin() + jEdge); + Zcoord_Index1.erase (Zcoord_Index1.begin() + jEdge); + Variable_Index1.erase (Variable_Index1.begin() + jEdge); + IGlobalID_Index1.erase (IGlobalID_Index1.begin() + jEdge); + JGlobalID_Index1.erase (JGlobalID_Index1.begin() + jEdge); + + Remove = true; break; + } + if (Remove) break; + } + if (Remove) break; + } + + } while (Remove == true); + + if (Xcoord_Index0.size() != 1) { + + /*--- Rotate from the Y-Z plane to the X-Z plane to reuse the rest of subroutines ---*/ + + if (config->GetGeo_Description() == FUSELAGE) { + su2double Angle = -0.5*PI_NUMBER; + for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { + su2double XCoord = Xcoord_Index0[iEdge]*cos(Angle) - Ycoord_Index0[iEdge]*sin(Angle); + su2double YCoord = Ycoord_Index0[iEdge]*cos(Angle) + Xcoord_Index0[iEdge]*sin(Angle); + su2double ZCoord = Zcoord_Index0[iEdge]; + Xcoord_Index0[iEdge] = XCoord; Ycoord_Index0[iEdge] = YCoord; Zcoord_Index0[iEdge] = ZCoord; + XCoord = Xcoord_Index1[iEdge]*cos(Angle) - Ycoord_Index1[iEdge]*sin(Angle); + YCoord = Ycoord_Index1[iEdge]*cos(Angle) + Xcoord_Index1[iEdge]*sin(Angle); + ZCoord = Zcoord_Index1[iEdge]; + Xcoord_Index1[iEdge] = XCoord; Ycoord_Index1[iEdge] = YCoord; Zcoord_Index1[iEdge] = ZCoord; + } + } + + /*--- Rotate nacelle secction to a X-Z plane to reuse the rest of subroutines ---*/ + + + if (config->GetGeo_Description() == NACELLE) { + + su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180; + su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180; + su2double Theta_deg = atan2(Plane_Normal[1],-Plane_Normal[2])/PI_NUMBER*180 + 180; + su2double Roll_Angle = 0.5*PI_NUMBER - Theta_deg*PI_NUMBER/180; + + su2double XCoord_Trans, YCoord_Trans, ZCoord_Trans, XCoord_Trans_Tilt, YCoord_Trans_Tilt, ZCoord_Trans_Tilt, + XCoord_Trans_Tilt_Toe, YCoord_Trans_Tilt_Toe, ZCoord_Trans_Tilt_Toe, XCoord, YCoord, ZCoord; + + for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { + + /*--- First point of the edge ---*/ + + /*--- Translate to the origin ---*/ + + XCoord_Trans = Xcoord_Index0[iEdge] - config->GetNacelleLocation(0); + YCoord_Trans = Ycoord_Index0[iEdge] - config->GetNacelleLocation(1); + ZCoord_Trans = Zcoord_Index0[iEdge] - config->GetNacelleLocation(2); + + /*--- Apply tilt angle ---*/ + + XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle); + YCoord_Trans_Tilt = YCoord_Trans; + ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle); + + /*--- Apply toe angle ---*/ + + XCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*cos(Toe_Angle) - YCoord_Trans_Tilt*sin(Toe_Angle); + YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle); + ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt; + + /*--- Rotate to X-Z plane (roll) ---*/ + + XCoord = XCoord_Trans_Tilt_Toe; + YCoord = YCoord_Trans_Tilt_Toe*cos(Roll_Angle) - ZCoord_Trans_Tilt_Toe*sin(Roll_Angle); + ZCoord = YCoord_Trans_Tilt_Toe*sin(Roll_Angle) + ZCoord_Trans_Tilt_Toe*cos(Roll_Angle); + + /*--- Update coordinates ---*/ + + Xcoord_Index0[iEdge] = XCoord; Ycoord_Index0[iEdge] = YCoord; Zcoord_Index0[iEdge] = ZCoord; + + /*--- Second point of the edge ---*/ + + /*--- Translate to the origin ---*/ + + XCoord_Trans = Xcoord_Index1[iEdge] - config->GetNacelleLocation(0); + YCoord_Trans = Ycoord_Index1[iEdge] - config->GetNacelleLocation(1); + ZCoord_Trans = Zcoord_Index1[iEdge] - config->GetNacelleLocation(2); + + /*--- Apply tilt angle ---*/ + + XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle); + YCoord_Trans_Tilt = YCoord_Trans; + ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle); + + /*--- Apply toe angle ---*/ + + XCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*cos(Toe_Angle) - YCoord_Trans_Tilt*sin(Toe_Angle); + YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle); + ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt; + + /*--- Rotate to X-Z plane (roll) ---*/ + + XCoord = XCoord_Trans_Tilt_Toe; + YCoord = YCoord_Trans_Tilt_Toe*cos(Roll_Angle) - ZCoord_Trans_Tilt_Toe*sin(Roll_Angle); + ZCoord = YCoord_Trans_Tilt_Toe*sin(Roll_Angle) + ZCoord_Trans_Tilt_Toe*cos(Roll_Angle); + + /*--- Update coordinates ---*/ + + Xcoord_Index1[iEdge] = XCoord; Ycoord_Index1[iEdge] = YCoord; Zcoord_Index1[iEdge] = ZCoord; + + } + } + + + /*--- Identify the extreme of the curve and close it ---*/ + + Conection_Index0.reserve(Xcoord_Index0.size()+1); + Conection_Index1.reserve(Xcoord_Index0.size()+1); + + for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { + Conection_Index0[iEdge] = 0; + Conection_Index1[iEdge] = 0; + } + + for (iEdge = 0; iEdge < Xcoord_Index0.size()-1; iEdge++) { + for (jEdge = iEdge+1; jEdge < Xcoord_Index0.size(); jEdge++) { + + if (((IGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge])) || + ((IGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]))) + { Conection_Index0[iEdge]++; Conection_Index0[jEdge]++; } + + if (((IGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge])) || + ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]))) + { Conection_Index0[iEdge]++; Conection_Index1[jEdge]++; } + + if (((IGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge])) || + ((IGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]))) + { Conection_Index1[iEdge]++; Conection_Index0[jEdge]++; } + + if (((IGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge])) || + ((IGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]))) + { Conection_Index1[iEdge]++; Conection_Index1[jEdge]++; } + + } + } + + /*--- Connect extremes of the curves ---*/ + + /*--- First: Identify the extremes of the curve in the extra vector ---*/ + + for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { + if (Conection_Index0[iEdge] == 0) { + XcoordExtra.push_back(Xcoord_Index0[iEdge]); + YcoordExtra.push_back(Ycoord_Index0[iEdge]); + ZcoordExtra.push_back(Zcoord_Index0[iEdge]); + VariableExtra.push_back(Variable_Index0[iEdge]); + IGlobalIDExtra.push_back(IGlobalID_Index0[iEdge]); + JGlobalIDExtra.push_back(JGlobalID_Index0[iEdge]); + AddExtra.push_back(true); + } + if (Conection_Index1[iEdge] == 0) { + XcoordExtra.push_back(Xcoord_Index1[iEdge]); + YcoordExtra.push_back(Ycoord_Index1[iEdge]); + ZcoordExtra.push_back(Zcoord_Index1[iEdge]); + VariableExtra.push_back(Variable_Index1[iEdge]); + IGlobalIDExtra.push_back(IGlobalID_Index1[iEdge]); + JGlobalIDExtra.push_back(JGlobalID_Index1[iEdge]); + AddExtra.push_back(true); + } + } + + /*--- Second, if it is an open curve then find the closest point to an extreme to close it ---*/ + + if (XcoordExtra.size() > 1) { + + for (iEdge = 0; iEdge < XcoordExtra.size()-1; iEdge++) { + + su2double MinDist = 1E6; FoundEdge = false; EdgeDonor = 0; + for (jEdge = iEdge+1; jEdge < XcoordExtra.size(); jEdge++) { + Dist_Value = sqrt(pow(SU2_TYPE::GetValue(XcoordExtra[iEdge])-SU2_TYPE::GetValue(XcoordExtra[jEdge]), 2.0)); + if ((Dist_Value < MinDist) && (AddExtra[iEdge]) && (AddExtra[jEdge])) { + EdgeDonor = jEdge; FoundEdge = true; + } + } + + if (FoundEdge) { + + /*--- Add first point of the new edge ---*/ + + Xcoord_Index0.push_back (XcoordExtra[iEdge]); + Ycoord_Index0.push_back (YcoordExtra[iEdge]); + Zcoord_Index0.push_back (ZcoordExtra[iEdge]); + Variable_Index0.push_back (VariableExtra[iEdge]); + IGlobalID_Index0.push_back (IGlobalIDExtra[iEdge]); + JGlobalID_Index0.push_back (JGlobalIDExtra[iEdge]); + AddExtra[iEdge] = false; + + /*--- Add second (closest) point of the new edge ---*/ + + Xcoord_Index1.push_back (XcoordExtra[EdgeDonor]); + Ycoord_Index1.push_back (YcoordExtra[EdgeDonor]); + Zcoord_Index1.push_back (ZcoordExtra[EdgeDonor]); + Variable_Index1.push_back (VariableExtra[EdgeDonor]); + IGlobalID_Index1.push_back (IGlobalIDExtra[EdgeDonor]); + JGlobalID_Index1.push_back (JGlobalIDExtra[EdgeDonor]); + AddExtra[EdgeDonor] = false; + + } + + } + + } + + else if (XcoordExtra.size() == 1) { + cout <<"There cutting system has failed, there is an incomplete curve (not used)." << endl; + } + + /*--- Find and add the trailing edge to to the list + and the contect the first point to the trailing edge ---*/ + + Trailing_Point = 0; Trailing_Coord = Xcoord_Index0[0]; + for (iEdge = 1; iEdge < Xcoord_Index0.size(); iEdge++) { + if (Xcoord_Index0[iEdge] > Trailing_Coord) { + Trailing_Point = iEdge; Trailing_Coord = Xcoord_Index0[iEdge]; + } + } + + Xcoord_Airfoil.push_back(Xcoord_Index0[Trailing_Point]); + Ycoord_Airfoil.push_back(Ycoord_Index0[Trailing_Point]); + Zcoord_Airfoil.push_back(Zcoord_Index0[Trailing_Point]); + Variable_Airfoil.push_back(Variable_Index0[Trailing_Point]); + IGlobalID_Airfoil.push_back(IGlobalID_Index0[Trailing_Point]); + JGlobalID_Airfoil.push_back(JGlobalID_Index0[Trailing_Point]); + + Xcoord_Airfoil.push_back(Xcoord_Index1[Trailing_Point]); + Ycoord_Airfoil.push_back(Ycoord_Index1[Trailing_Point]); + Zcoord_Airfoil.push_back(Zcoord_Index1[Trailing_Point]); + Variable_Airfoil.push_back(Variable_Index1[Trailing_Point]); + IGlobalID_Airfoil.push_back(IGlobalID_Index1[Trailing_Point]); + JGlobalID_Airfoil.push_back(JGlobalID_Index1[Trailing_Point]); + + Xcoord_Index0.erase (Xcoord_Index0.begin() + Trailing_Point); + Ycoord_Index0.erase (Ycoord_Index0.begin() + Trailing_Point); + Zcoord_Index0.erase (Zcoord_Index0.begin() + Trailing_Point); + Variable_Index0.erase (Variable_Index0.begin() + Trailing_Point); + IGlobalID_Index0.erase (IGlobalID_Index0.begin() + Trailing_Point); + JGlobalID_Index0.erase (JGlobalID_Index0.begin() + Trailing_Point); + + Xcoord_Index1.erase (Xcoord_Index1.begin() + Trailing_Point); + Ycoord_Index1.erase (Ycoord_Index1.begin() + Trailing_Point); + Zcoord_Index1.erase (Zcoord_Index1.begin() + Trailing_Point); + Variable_Index1.erase (Variable_Index1.begin() + Trailing_Point); + IGlobalID_Index1.erase (IGlobalID_Index1.begin() + Trailing_Point); + JGlobalID_Index1.erase (JGlobalID_Index1.begin() + Trailing_Point); + + + /*--- Algorithm for adding the rest of the points ---*/ + + do { + + /*--- Last added point in the list ---*/ + + Airfoil_Point = Xcoord_Airfoil.size() - 1; + + /*--- Find the closest point ---*/ + + Found_Edge = false; + + for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { + + if (((IGlobalID_Index0[iEdge] == IGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index0[iEdge] == JGlobalID_Airfoil[Airfoil_Point])) || + ((IGlobalID_Index0[iEdge] == JGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index0[iEdge] == IGlobalID_Airfoil[Airfoil_Point]))) { + Next_Edge = iEdge; Found_Edge = true; Index = 0; break; + } + + if (((IGlobalID_Index1[iEdge] == IGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index1[iEdge] == JGlobalID_Airfoil[Airfoil_Point])) || + ((IGlobalID_Index1[iEdge] == JGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index1[iEdge] == IGlobalID_Airfoil[Airfoil_Point]))) { + Next_Edge = iEdge; Found_Edge = true; Index = 1; break; + } + + } + + /*--- Add and remove the next point to the list and the next point in the edge ---*/ + + if (Found_Edge) { + + if (Index == 0) { + Xcoord_Airfoil.push_back(Xcoord_Index1[Next_Edge]); + Ycoord_Airfoil.push_back(Ycoord_Index1[Next_Edge]); + Zcoord_Airfoil.push_back(Zcoord_Index1[Next_Edge]); + Variable_Airfoil.push_back(Variable_Index1[Next_Edge]); + IGlobalID_Airfoil.push_back(IGlobalID_Index1[Next_Edge]); + JGlobalID_Airfoil.push_back(JGlobalID_Index1[Next_Edge]); + } + + if (Index == 1) { + Xcoord_Airfoil.push_back(Xcoord_Index0[Next_Edge]); + Ycoord_Airfoil.push_back(Ycoord_Index0[Next_Edge]); + Zcoord_Airfoil.push_back(Zcoord_Index0[Next_Edge]); + Variable_Airfoil.push_back(Variable_Index0[Next_Edge]); + IGlobalID_Airfoil.push_back(IGlobalID_Index0[Next_Edge]); + JGlobalID_Airfoil.push_back(JGlobalID_Index0[Next_Edge]); + } + + Xcoord_Index0.erase(Xcoord_Index0.begin() + Next_Edge); + Ycoord_Index0.erase(Ycoord_Index0.begin() + Next_Edge); + Zcoord_Index0.erase(Zcoord_Index0.begin() + Next_Edge); + Variable_Index0.erase(Variable_Index0.begin() + Next_Edge); + IGlobalID_Index0.erase(IGlobalID_Index0.begin() + Next_Edge); + JGlobalID_Index0.erase(JGlobalID_Index0.begin() + Next_Edge); + + Xcoord_Index1.erase(Xcoord_Index1.begin() + Next_Edge); + Ycoord_Index1.erase(Ycoord_Index1.begin() + Next_Edge); + Zcoord_Index1.erase(Zcoord_Index1.begin() + Next_Edge); + Variable_Index1.erase(Variable_Index1.begin() + Next_Edge); + IGlobalID_Index1.erase(IGlobalID_Index1.begin() + Next_Edge); + JGlobalID_Index1.erase(JGlobalID_Index1.begin() + Next_Edge); + + } + else { break; } + + } while (Xcoord_Index0.size() != 0); + + /*--- Clean the vector before using them again for storing the upper or the lower side ---*/ + + Xcoord_Index0.clear(); Ycoord_Index0.clear(); Zcoord_Index0.clear(); Variable_Index0.clear(); IGlobalID_Index0.clear(); JGlobalID_Index0.clear(); + Xcoord_Index1.clear(); Ycoord_Index1.clear(); Zcoord_Index1.clear(); Variable_Index1.clear(); IGlobalID_Index1.clear(); JGlobalID_Index1.clear(); + + } + + } + + AD_END_PASSIVE + +} + +void CGeometry::RegisterCoordinates(CConfig *config) { + unsigned short iDim; + unsigned long iPoint; + bool input = true; + bool push_index = config->GetMultizone_Problem()? false : true; + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + AD::RegisterInput(node[iPoint]->GetCoord()[iDim], push_index); + } + if(!push_index) { + for (iDim = 0; iDim < nDim; iDim++) { + node[iPoint]->SetIndex(input); + } + } + } +} + +void CGeometry::RegisterOutput_Coordinates(CConfig *config){ + unsigned short iDim; + unsigned long iPoint; + + for (iPoint = 0; iPoint < nPoint; iPoint++){ + if(config->GetMultizone_Problem()) { + for (iDim = 0; iDim < nDim; iDim++) { + AD::RegisterOutput(node[iPoint]->GetCoord()[iDim]); + } + } + else { + for (iDim = 0; iDim < nDim; iDim++) { + AD::RegisterOutput(node[iPoint]->GetCoord()[iDim]); + } + } + } +} + +void CGeometry::UpdateGeometry(CGeometry **geometry_container, CConfig *config) { + + unsigned short iMesh; + + geometry_container[MESH_0]->InitiateComms(geometry_container[MESH_0], config, COORDINATES); + geometry_container[MESH_0]->CompleteComms(geometry_container[MESH_0], config, COORDINATES); + if (config->GetGrid_Movement()){ + geometry_container[MESH_0]->InitiateComms(geometry_container[MESH_0], config, GRID_VELOCITY); + geometry_container[MESH_0]->CompleteComms(geometry_container[MESH_0], config, GRID_VELOCITY); + } + + geometry_container[MESH_0]->SetCoord_CG(); + geometry_container[MESH_0]->SetControlVolume(config, UPDATE); + geometry_container[MESH_0]->SetBoundControlVolume(config, UPDATE); + geometry_container[MESH_0]->SetMaxLength(config); + + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + /*--- Update the control volume structures ---*/ + + geometry_container[iMesh]->SetControlVolume(config,geometry_container[iMesh-1], UPDATE); + geometry_container[iMesh]->SetBoundControlVolume(config,geometry_container[iMesh-1], UPDATE); + geometry_container[iMesh]->SetCoord(geometry_container[iMesh-1]); + + } + + if (config->GetKind_Solver() == DISC_ADJ_RANS || config->GetKind_Solver() == DISC_ADJ_INC_RANS) + geometry_container[MESH_0]->ComputeWall_Distance(config); + +} + +void CGeometry::SetCustomBoundary(CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex; + string Marker_Tag; + + /*--- Initialize quantities for customized boundary conditions. + * Custom values are initialized with the default values specified in the config (avoiding non physical values) ---*/ + CustomBoundaryTemperature = new su2double*[nMarker]; + CustomBoundaryHeatFlux = new su2double*[nMarker]; + + for(iMarker=0; iMarker < nMarker; iMarker++){ + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + CustomBoundaryHeatFlux[iMarker] = NULL; + CustomBoundaryTemperature[iMarker] = NULL; + if(config->GetMarker_All_PyCustom(iMarker)){ + switch(config->GetMarker_All_KindBC(iMarker)){ + case HEAT_FLUX: + CustomBoundaryHeatFlux[iMarker] = new su2double[nVertex[iMarker]]; + for(iVertex=0; iVertex < nVertex[iMarker]; iVertex++){ + CustomBoundaryHeatFlux[iMarker][iVertex] = config->GetWall_HeatFlux(Marker_Tag); + } + break; + case ISOTHERMAL: + CustomBoundaryTemperature[iMarker] = new su2double[nVertex[iMarker]]; + for(iVertex=0; iVertex < nVertex[iMarker]; iVertex++){ + CustomBoundaryTemperature[iMarker][iVertex] = config->GetIsothermal_Temperature(Marker_Tag); + } + break; + case INLET_FLOW: + // This case is handled in the solver class. + break; + default: + cout << "WARNING: Marker " << Marker_Tag << " is not customizable. Using default behavior." << endl; + break; + } + } + } + +} + +void CGeometry::UpdateCustomBoundaryConditions(CGeometry **geometry_container, CConfig *config){ + + unsigned short iMGfine, iMGlevel, nMGlevel, iMarker; + + nMGlevel = config->GetnMGLevels(); + for (iMGlevel=1; iMGlevel <= nMGlevel; iMGlevel++){ + iMGfine = iMGlevel-1; + for(iMarker = 0; iMarker< config->GetnMarker_All(); iMarker++){ + if(config->GetMarker_All_PyCustom(iMarker)){ + switch(config->GetMarker_All_KindBC(iMarker)){ + case HEAT_FLUX: + geometry_container[iMGlevel]->SetMultiGridWallHeatFlux(geometry_container[iMGfine], iMarker); + break; + case ISOTHERMAL: + geometry_container[iMGlevel]->SetMultiGridWallTemperature(geometry_container[iMGfine], iMarker); + break; + // Inlet flow handled in solver class. + default: break; + } + } + } + } +} + + +void CGeometry::ComputeSurf_Straightness(CConfig *config, + bool print_on_screen) { + + bool RefUnitNormal_defined; + unsigned short iDim, + iMarker, + iMarker_Global, + nMarker_Global = config->GetnMarker_CfgFile(); + unsigned long iVertex; + constexpr passivedouble epsilon = 1.0e-6; + su2double Area; + string Local_TagBound, + Global_TagBound; + + vector Normal(nDim), + UnitNormal(nDim), + RefUnitNormal(nDim); + + /*--- Assume now that this boundary marker is straight. As soon as one + AreaElement is found that is not aligend with a Reference then it is + certain that the boundary marker is not straight and one can stop + searching. Another possibility is that this process doesn't own + any nodes of that boundary, in that case we also have to assume the + boundary is straight. + Any boundary type other than SYMMETRY_PLANE or EULER_WALL gets + the value false (or see cases specified in the conditional below) + which could be wrong. ---*/ + bound_is_straight.resize(nMarker); + fill(bound_is_straight.begin(), bound_is_straight.end(), true); + + /*--- Loop over all local markers ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + Local_TagBound = config->GetMarker_All_TagBound(iMarker); + + /*--- Marker has to be Symmetry or Euler. Additionally marker can't be a + moving surface and Grid Movement Elasticity is forbidden as well. All + other GridMovements are rigid. ---*/ + if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE || + config->GetMarker_All_KindBC(iMarker) == EULER_WALL) && + config->GetMarker_Moving_Bool(Local_TagBound) == false && + config->GetKind_GridMovement() != ELASTICITY) { + + /*--- Loop over all global markers, and find the local-global pair via + matching unique string tags. ---*/ + for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) { + + Global_TagBound = config->GetMarker_CfgFile_TagBound(iMarker_Global); + if (Local_TagBound == Global_TagBound) { + + RefUnitNormal_defined = false; + iVertex = 0; + + while(bound_is_straight[iMarker] == true && + iVertex < nVertex[iMarker]) { + + vertex[iMarker][iVertex]->GetNormal(Normal.data()); + UnitNormal = Normal; + + /*--- Compute unit normal. ---*/ + Area = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + Area += Normal[iDim]*Normal[iDim]; + Area = sqrt(Area); + + /*--- Negate for outward convention. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + UnitNormal[iDim] /= -Area; + + /*--- Check if unit normal is within tolerance of the Reference unit normal. + Reference unit normal = first unit normal found. ---*/ + if(RefUnitNormal_defined) { + for (iDim = 0; iDim < nDim; iDim++) { + if( abs(RefUnitNormal[iDim] - UnitNormal[iDim]) > epsilon ) { + bound_is_straight[iMarker] = false; + break; + } + } + } else { + RefUnitNormal = UnitNormal; //deep copy of values + RefUnitNormal_defined = true; + } + + iVertex++; + }//while iVertex + }//if Local == Global + }//for iMarker_Global + } else { + /*--- Enforce default value: false ---*/ + bound_is_straight[iMarker] = false; + }//if sym or euler ... + }//for iMarker + + /*--- Communicate results and print on screen. ---*/ + if(print_on_screen) { + + /*--- Additional vector which can later be MPI::Allreduce(d) to pring the results + on screen as nMarker (local) can vary across ranks. Default 'true' as it can + happen that a local rank does not contain an element of each surface marker. ---*/ + vector bound_is_straight_Global(nMarker_Global, true); + /*--- Match local with global tag bound and fill a Global Marker vector. ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + Local_TagBound = config->GetMarker_All_TagBound(iMarker); + for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) { + Global_TagBound = config->GetMarker_CfgFile_TagBound(iMarker_Global); + + if(Local_TagBound == Global_TagBound) + bound_is_straight_Global[iMarker_Global] = bound_is_straight[iMarker]; + + }//for iMarker_Global + }//for iMarker + + vector Buff_Send_isStraight(nMarker_Global), + Buff_Recv_isStraight(nMarker_Global); + + /*--- Cast to int as std::vector can be a special construct. MPI handling using + is more straight-forward. ---*/ + for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) + Buff_Send_isStraight[iMarker_Global] = static_cast (bound_is_straight_Global[iMarker_Global]); + + /*--- Product of type (bool) is equivalnt to a 'logical and' ---*/ + SU2_MPI::Allreduce(Buff_Send_isStraight.data(), Buff_Recv_isStraight.data(), + nMarker_Global, MPI_INT, MPI_PROD, MPI_COMM_WORLD); + + /*--- Print results on screen. ---*/ + if(rank == MASTER_NODE) { + for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) { + if (config->GetMarker_CfgFile_KindBC(config->GetMarker_CfgFile_TagBound(iMarker_Global)) == SYMMETRY_PLANE || + config->GetMarker_CfgFile_KindBC(config->GetMarker_CfgFile_TagBound(iMarker_Global)) == EULER_WALL) { + + cout << "Boundary marker " << config->GetMarker_CfgFile_TagBound(iMarker_Global) << " is"; + if(Buff_Recv_isStraight[iMarker_Global] == false) cout << " NOT"; + if(nDim == 2) cout << " a single straight." << endl; + if(nDim == 3) cout << " a single plane." << endl; + }//if sym or euler + }//for iMarker_Global + }//if rank==MASTER + }//if print_on_scren + +} + + +void CGeometry::ComputeSurf_Curvature(CConfig *config) { + unsigned short iMarker, iNeigh_Point, iDim, iNode, iNeighbor_Nodes, Neighbor_Node; + unsigned long Neighbor_Point, iVertex, iPoint, jPoint, iElem_Bound, iEdge, nLocalVertex, MaxLocalVertex , *Buffer_Send_nVertex, *Buffer_Receive_nVertex, TotalnPointDomain; + int iProcessor, nProcessor; + vector Point_NeighborList, Elem_NeighborList, Point_Triangle, Point_Edge, Point_Critical; + vector::iterator it; + su2double U[3] = {0.0,0.0,0.0}, V[3] = {0.0,0.0,0.0}, W[3] = {0.0,0.0,0.0}, Length_U, Length_V, Length_W, CosValue, Angle_Value, *K, *Angle_Defect, *Area_Vertex, *Angle_Alpha, *Angle_Beta, **NormalMeanK, MeanK, GaussK, MaxPrinK, cot_alpha, cot_beta, delta, X1, X2, X3, Y1, Y2, Y3, radius, *Buffer_Send_Coord, *Buffer_Receive_Coord, *Coord, Dist, MinDist, MaxK, MinK, SigmaK; + bool *Check_Edge; + + bool fea = ((config->GetKind_Solver()==FEM_ELASTICITY) || (config->GetKind_Solver()==DISC_ADJ_FEM)); + + /*--- Allocate surface curvature ---*/ + K = new su2double [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) K[iPoint] = 0.0; + + if (nDim == 2) { + + /*--- Loop over all the markers ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + + /*--- Loop through all marker vertices again, this time also + finding the neighbors of each node.---*/ + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + + if (node[iPoint]->GetDomain()) { + /*--- Loop through neighbors. In 2-D, there should be 2 nodes on either + side of this vertex that lie on the same surface. ---*/ + Point_Edge.clear(); + + for (iNeigh_Point = 0; iNeigh_Point < node[iPoint]->GetnPoint(); iNeigh_Point++) { + Neighbor_Point = node[iPoint]->GetPoint(iNeigh_Point); + + /*--- Check if this neighbor lies on the surface. If so, + add to the list of neighbors. ---*/ + if (node[Neighbor_Point]->GetPhysicalBoundary()) { + Point_Edge.push_back(Neighbor_Point); + } + + } + + if (Point_Edge.size() == 2) { + + /*--- Compute the curvature using three points ---*/ + X1 = node[iPoint]->GetCoord(0); + X2 = node[Point_Edge[0]]->GetCoord(0); + X3 = node[Point_Edge[1]]->GetCoord(0); + Y1 = node[iPoint]->GetCoord(1); + Y2 = node[Point_Edge[0]]->GetCoord(1); + Y3 = node[Point_Edge[1]]->GetCoord(1); + + radius = sqrt(((X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1))* + ((X2-X3)*(X2-X3) + (Y2-Y3)*(Y2-Y3))* + ((X3-X1)*(X3-X1) + (Y3-Y1)*(Y3-Y1)))/ + (2.0*fabs(X1*Y2+X2*Y3+X3*Y1-X1*Y3-X2*Y1-X3*Y2)+EPS); + + K[iPoint] = 1.0/radius; + node[iPoint]->SetCurvature(K[iPoint]); + } + + } + + } + + } + + } + + } + + else { + + Angle_Defect = new su2double [nPoint]; + Area_Vertex = new su2double [nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + Angle_Defect[iPoint] = 2*PI_NUMBER; + Area_Vertex[iPoint] = 0.0; + } + + Angle_Alpha = new su2double [nEdge]; + Angle_Beta = new su2double [nEdge]; + Check_Edge = new bool [nEdge]; + for (iEdge = 0; iEdge < nEdge; iEdge++) { + Angle_Alpha[iEdge] = 0.0; + Angle_Beta[iEdge] = 0.0; + Check_Edge[iEdge] = true; + } + + NormalMeanK = new su2double *[nPoint]; + for (iPoint = 0; iPoint < nPoint; iPoint++) { + NormalMeanK[iPoint] = new su2double [nDim]; + for (iDim = 0; iDim < nDim; iDim++) { + NormalMeanK[iPoint][iDim] = 0.0; + } + } + + /*--- Loop over all the markers ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + + /*--- Loop over all the boundary elements ---*/ + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + + /*--- Only triangles ---*/ + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { + + /*--- Loop over all the nodes of the boundary element ---*/ + for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { + + iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); + + Point_Triangle.clear(); + + for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { + Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); + Neighbor_Point = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); + Point_Triangle.push_back(Neighbor_Point); + } + + iEdge = FindEdge(Point_Triangle[0], Point_Triangle[1]); + + for (iDim = 0; iDim < nDim; iDim++) { + U[iDim] = node[Point_Triangle[0]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); + V[iDim] = node[Point_Triangle[1]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); + } + + W[0] = 0.5*(U[1]*V[2]-U[2]*V[1]); W[1] = -0.5*(U[0]*V[2]-U[2]*V[0]); W[2] = 0.5*(U[0]*V[1]-U[1]*V[0]); + + Length_U = 0.0; Length_V = 0.0; Length_W = 0.0; CosValue = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { Length_U += U[iDim]*U[iDim]; Length_V += V[iDim]*V[iDim]; Length_W += W[iDim]*W[iDim]; } + Length_U = sqrt(Length_U); Length_V = sqrt(Length_V); Length_W = sqrt(Length_W); + for (iDim = 0; iDim < nDim; iDim++) { U[iDim] /= Length_U; V[iDim] /= Length_V; CosValue += U[iDim]*V[iDim]; } + if (CosValue >= 1.0) CosValue = 1.0; + if (CosValue <= -1.0) CosValue = -1.0; + + Angle_Value = acos(CosValue); + Area_Vertex[iPoint] += Length_W; + Angle_Defect[iPoint] -= Angle_Value; + if (Angle_Alpha[iEdge] == 0.0) Angle_Alpha[iEdge] = Angle_Value; + else Angle_Beta[iEdge] = Angle_Value; + + } + } + } + } + } + + /*--- Compute mean curvature ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { + if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { + for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { + iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); + + for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { + Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); + jPoint = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); + + iEdge = FindEdge(iPoint, jPoint); + + if (Check_Edge[iEdge]) { + + Check_Edge[iEdge] = false; + + if (tan(Angle_Alpha[iEdge]) != 0.0) cot_alpha = 1.0/tan(Angle_Alpha[iEdge]); else cot_alpha = 0.0; + if (tan(Angle_Beta[iEdge]) != 0.0) cot_beta = 1.0/tan(Angle_Beta[iEdge]); else cot_beta = 0.0; + + /*--- iPoint, and jPoint ---*/ + for (iDim = 0; iDim < nDim; iDim++) { + if (Area_Vertex[iPoint] != 0.0) NormalMeanK[iPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[iPoint]->GetCoord(iDim) - node[jPoint]->GetCoord(iDim)) / Area_Vertex[iPoint]; + if (Area_Vertex[jPoint] != 0.0) NormalMeanK[jPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[jPoint]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim)) / Area_Vertex[jPoint]; + } + } + + } + } + } + } + } + } + + /*--- Compute Gauss, mean, max and min principal curvature, + and set the list of critical points ---*/ + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + + if (node[iPoint]->GetDomain()) { + + if (Area_Vertex[iPoint] != 0.0) GaussK = 3.0*Angle_Defect[iPoint]/Area_Vertex[iPoint]; + else GaussK = 0.0; + + MeanK = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + MeanK += NormalMeanK[iPoint][iDim]*NormalMeanK[iPoint][iDim]; + MeanK = sqrt(MeanK); + + delta = max((MeanK*MeanK - GaussK), 0.0); + + MaxPrinK = MeanK + sqrt(delta); + + /*--- Store the curvature value ---*/ + K[iPoint] = MaxPrinK; + node[iPoint]->SetCurvature(K[iPoint]); + } + + } + } + } + + delete [] Angle_Defect; + delete [] Area_Vertex; + delete [] Angle_Alpha; + delete [] Angle_Beta; + delete [] Check_Edge; + + for (iPoint = 0; iPoint < nPoint; iPoint++) + delete [] NormalMeanK[iPoint]; + delete [] NormalMeanK; + + } + + /*--- Sharp edge detection is based in the statistical + distribution of the curvature ---*/ + + MaxK = K[0]; MinK = K[0]; MeanK = 0.0; TotalnPointDomain = 0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + MaxK = max(MaxK, fabs(K[iPoint])); + MinK = min(MinK, fabs(K[iPoint])); + MeanK += fabs(K[iPoint]); + TotalnPointDomain++; + } + } + } + } + +#ifdef HAVE_MPI + su2double MyMeanK = MeanK; MeanK = 0.0; + su2double MyMaxK = MaxK; MaxK = 0.0; + unsigned long MynPointDomain = TotalnPointDomain; TotalnPointDomain = 0; + SU2_MPI::Allreduce(&MyMeanK, &MeanK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MyMaxK, &MaxK, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&MynPointDomain, &TotalnPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#endif + + /*--- Compute the mean ---*/ + MeanK /= su2double(TotalnPointDomain); + + /*--- Compute the standard deviation ---*/ + SigmaK = 0.0; + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + SigmaK += (fabs(K[iPoint]) - MeanK) * (fabs(K[iPoint]) - MeanK); + } + } + } + } + +#ifdef HAVE_MPI + su2double MySigmaK = SigmaK; SigmaK = 0.0; + SU2_MPI::Allreduce(&MySigmaK, &SigmaK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); +#endif + + SigmaK = sqrt(SigmaK/su2double(TotalnPointDomain)); + + if ((rank == MASTER_NODE) && (!fea)) + cout << "Max K: " << MaxK << ". Mean K: " << MeanK << ". Standard deviation K: " << SigmaK << "." << endl; + + Point_Critical.clear(); + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + if (fabs(K[iPoint]) > MeanK + config->GetRefSharpEdges()*SigmaK) { + Point_Critical.push_back(iPoint); + } + } + } + } + } + + /*--- Variables and buffers needed for MPI ---*/ + +#ifdef HAVE_MPI + SU2_MPI::Comm_size(MPI_COMM_WORLD, &nProcessor); +#else + nProcessor = 1; +#endif + + Buffer_Send_nVertex = new unsigned long [1]; + Buffer_Receive_nVertex = new unsigned long [nProcessor]; + + /*--- Count the total number of critical edge nodes. ---*/ + + nLocalVertex = Point_Critical.size(); + Buffer_Send_nVertex[0] = nLocalVertex; + + /*--- Communicate to all processors the total number of critical edge nodes. ---*/ + +#ifdef HAVE_MPI + MaxLocalVertex = 0; + SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); + SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); +#else + MaxLocalVertex = nLocalVertex; + Buffer_Receive_nVertex[0] = nLocalVertex; +#endif + + + /*--- Create and initialize to zero some buffers to hold the coordinates + of the boundary nodes that are communicated from each partition (all-to-all). ---*/ + + Buffer_Send_Coord = new su2double [MaxLocalVertex*nDim]; + Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*nDim]; + +#ifdef HAVE_MPI + unsigned long nBuffer = MaxLocalVertex*nDim; +#endif + + for (iVertex = 0; iVertex < MaxLocalVertex; iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) { + Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; + } + } + + /*--- Retrieve and store the coordinates of the sharp edges boundary nodes on + the local partition and broadcast them to all partitions. ---*/ + + for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { + iPoint = Point_Critical[iVertex]; + for (iDim = 0; iDim < nDim; iDim++) + Buffer_Send_Coord[iVertex*nDim+iDim] = node[iPoint]->GetCoord(iDim); + } + +#ifdef HAVE_MPI + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); +#else + for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { + for (iDim = 0; iDim < nDim; iDim++) { + Buffer_Receive_Coord[iVertex*nDim+iDim] = Buffer_Send_Coord[iVertex*nDim+iDim]; + } + } +#endif + + /*--- Loop over all interior mesh nodes on the local partition and compute + the distances to each of the no-slip boundary nodes in the entire mesh. + Store the minimum distance to the wall for each interior mesh node. ---*/ + + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { + Coord = node[iPoint]->GetCoord(); + + MinDist = 1E20; + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { + for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { + Dist = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + Dist += (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim])* + (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim]); + } + if (Dist!=0.0) Dist = sqrt(Dist); + else Dist = 0.0; + if (Dist < MinDist) MinDist = Dist; + } + } + node[iPoint]->SetSharpEdge_Distance(MinDist); + } + + /*--- Deallocate Max curvature ---*/ + delete[] K; + + /*--- Deallocate the buffers needed for the MPI communication. ---*/ + delete[] Buffer_Send_Coord; + delete[] Buffer_Receive_Coord; + delete[] Buffer_Send_nVertex; + delete[] Buffer_Receive_nVertex; + +} + +void CGeometry::FilterValuesAtElementCG(const vector &filter_radius, + const vector > &kernels, + const unsigned short search_limit, + const su2double *input_values, + su2double *output_values) const +{ + /*--- Apply a filter to "input_values". The filter is an averaging process over the neighbourhood + of each element, which is a circle in 2D and a sphere in 3D of radius "filter_radius". + The filter is characterized by its kernel, i.e. how the weights are computed. Multiple kernels + can be specified in which case they are applied sequentially (each one being applied to the + output values of the previous filter. ---*/ + + unsigned long iElem, iElem_global, limited_searches = 0; + + /*--- Initialize output values and check if we need to do any more work than that ---*/ + for (iElem=0; iElem neighbour_start; + long *neighbour_idx = NULL; + GetGlobalElementAdjacencyMatrix(neighbour_start,neighbour_idx); + + /*--- Element centroids and volumes ---*/ + su2double *cg_elem = new su2double [Global_nElemDomain*nDim], + *vol_elem = new su2double [Global_nElemDomain]; + + /*--- Initialize ---*/ + for(iElem=0; iElemGetGlobalIndex(); + for(unsigned short iDim=0; iDimGetCG(iDim); + vol_elem[iElem_global] = elem[iElem]->GetVolume(); + } +#ifdef HAVE_MPI + /*--- Share with all processors ---*/ + { + su2double *buffer = NULL, *tmp = NULL; + + buffer = new su2double [Global_nElemDomain*nDim]; + SU2_MPI::Allreduce(cg_elem,buffer,Global_nElemDomain*nDim,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); + tmp = cg_elem; cg_elem = buffer; delete [] tmp; + + buffer = new su2double [Global_nElemDomain]; + SU2_MPI::Allreduce(vol_elem,buffer,Global_nElemDomain,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); + tmp = vol_elem; vol_elem = buffer; delete [] tmp; + } + + /*--- Account for the duplication introduced by the halo elements and the + reduction using MPI_SUM, which is required to maintain differentiabillity. ---*/ + vector halo_detect(Global_nElemDomain); + { + vector buffer(Global_nElemDomain,0); + for(iElem=0; iElemGetGlobalIndex()] = 1; + MPI_Allreduce(buffer.data(),halo_detect.data(),Global_nElemDomain,MPI_CHAR,MPI_SUM,MPI_COMM_WORLD); + } + for(iElem=0; iElem is_neighbor(Global_nElemDomain,false); + + for (unsigned long iKernel=0; iKernelGetGlobalIndex()] = output_values[iElem]; +#ifdef HAVE_MPI + /*--- Share with all processors ---*/ + { + su2double *buffer = new su2double [Global_nElemDomain], *tmp = NULL; + SU2_MPI::Allreduce(work_values,buffer,Global_nElemDomain,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); + tmp = work_values; work_values = buffer; delete [] tmp; + } + /*--- Account for duplication ---*/ + for(iElem=0; iElemGetGlobalIndex(); + + /*--- Find the neighbours of iElem ---*/ + vector neighbours; + limited_searches += !GetRadialNeighbourhood(iElem_global, SU2_TYPE::GetValue(kernel_radius), + search_limit, neighbour_start, neighbour_idx, cg_elem, neighbours, is_neighbor); + + /*--- Apply the kernel ---*/ + su2double weight = 0.0, numerator = 0.0, denominator = 0.0; + + switch ( kernel_type ) { + /*--- distance-based kernels (weighted averages) ---*/ + case CONSTANT_WEIGHT_FILTER: case CONICAL_WEIGHT_FILTER: case GAUSSIAN_WEIGHT_FILTER: + + for (auto idx : neighbours) + { + su2double distance = 0.0; + for (unsigned short iDim=0; iDim0) + cout << "Warning: The filter radius was limited for " << limited_searches + << " elements (" << limited_searches/(0.01*Global_nElemDomain) << "%).\n"; + + delete [] neighbour_idx; + delete [] cg_elem; + delete [] vol_elem; + delete [] work_values; +} + +void CGeometry::GetGlobalElementAdjacencyMatrix(vector &neighbour_start, + long *&neighbour_idx) const +{ + if ( neighbour_idx != NULL ) + SU2_MPI::Error("neighbour_idx is expected to be NULL, stopping to avoid a potential memory leak",CURRENT_FUNCTION); + + unsigned long iElem, iElem_global; + + /*--- Determine how much space we need for the adjacency matrix by counting the + neighbours of each element, i.e. its number of faces---*/ + unsigned short *nFaces_elem = new unsigned short [Global_nElemDomain]; + + for(iElem=0; iElemGetGlobalIndex(); + nFaces_elem[iElem_global] = elem[iElem]->GetnFaces(); + } +#ifdef HAVE_MPI + /*--- Share with all processors ---*/ + { + unsigned short *buffer = new unsigned short [Global_nElemDomain], *tmp = NULL; + MPI_Allreduce(nFaces_elem,buffer,Global_nElemDomain,MPI_UNSIGNED_SHORT,MPI_MAX,MPI_COMM_WORLD); + /*--- swap pointers and delete old data to keep the same variable name after reduction ---*/ + tmp = nFaces_elem; nFaces_elem = buffer; delete [] tmp; + } +#endif + + /*--- Vector with the addresses of the start of the neighbours of a given element. + This is generated by a cumulative sum of the neighbour count. ---*/ + neighbour_start.resize(Global_nElemDomain+1); + + neighbour_start[0] = 0; + for(iElem=0; iElemGetGlobalIndex(); + unsigned long start_pos = neighbour_start[iElem_global]; + + for(unsigned short iFace=0; iFaceGetnFaces(); ++iFace) + { + long neighbour = elem[iElem]->GetNeighbor_Elements(iFace); + + if ( neighbour>=0 ) { + neighbour_idx[start_pos+iFace] = elem[neighbour]->GetGlobalIndex(); + } + } + } +#ifdef HAVE_MPI + /*--- Share with all processors ---*/ + { + long *buffer = new long [matrix_size], *tmp = NULL; + MPI_Allreduce(neighbour_idx,buffer,matrix_size,MPI_LONG,MPI_MAX,MPI_COMM_WORLD); + tmp = neighbour_idx; neighbour_idx = buffer; delete [] tmp; + } +#endif +} + +bool CGeometry::GetRadialNeighbourhood(const unsigned long iElem_global, + const passivedouble radius, + size_t search_limit, + const vector &neighbour_start, + const long *neighbour_idx, + const su2double *cg_elem, + vector &neighbours, + vector &is_neighbor) const +{ + /*--- Validate inputs if we are debugging. ---*/ + assert(neighbour_start.size() == Global_nElemDomain+1 && + neighbour_idx != nullptr && cg_elem != nullptr && + is_neighbor.size() == Global_nElemDomain && "invalid inputs"); + + /*--- 0 search_limit means "unlimited" (it will probably + stop once it gathers the entire domain, probably). ---*/ + if (!search_limit) search_limit = numeric_limits::max(); + + /*--- Center of the search ---*/ + neighbours.clear(); + neighbours.push_back(iElem_global); + is_neighbor[iElem_global] = true; + + passivedouble X0[3] = {0.0, 0.0, 0.0}; + for (unsigned short iDim=0; iDim candidates; + + for (auto it = neighbours.begin()+start; it!=neighbours.end(); ++it) { + /*--- scan row of the adjacency matrix of element *it ---*/ + for (auto i = neighbour_start[*it]; i < neighbour_start[(*it)+1]; ++i) { + auto idx = neighbour_idx[i]; + if (idx>=0) if (!is_neighbor[idx]) { + candidates.push_back(idx); + /*--- mark as neighbour for now to avoid duplicate candidates. ---*/ + is_neighbor[idx] = true; + } + } + } + /*--- update start position to fetch next degree candidates. ---*/ + start = neighbours.size(); + + /*--- Add candidates within "radius" of X0, if none qualifies we are "finished". ---*/ + finished = true; + for (auto idx : candidates) + { + /*--- passivedouble as we only need to compare "distance". ---*/ + passivedouble distance = 0.0; + for (unsigned short iDim=0; iDimGetVTK_Type()) { + case TRIANGLE: element = elements[0]; break; + case QUADRILATERAL: element = elements[1]; break; + case TETRAHEDRON: element = elements[0]; break; + case PYRAMID: element = elements[1]; break; + case PRISM: element = elements[2]; break; + case HEXAHEDRON: element = elements[3]; break; + default: + SU2_MPI::Error("Cannot compute the area/volume of a 1D element.",CURRENT_FUNCTION); + } + /*--- Set the nodal coordinates of the element ---*/ + for (unsigned short iNode=0; iNodeGetnNodes(); ++iNode) { + unsigned long node_idx = elem[iElem]->GetNode(iNode); + for (unsigned short iDim=0; iDimGetCoord(iDim); + element->SetRef_Coord(iNode, iDim, coord); + } + } + /*--- Compute ---*/ + if(nDim==2) elem[iElem]->SetVolume(element->ComputeArea()); + else elem[iElem]->SetVolume(element->ComputeVolume()); + } + + delete elements[0]; + delete elements[1]; + if (nDim==3) { + delete elements[2]; + delete elements[3]; + } +} + +void CGeometry::UpdateBoundaries(CConfig *config){ + + unsigned short iMarker; + unsigned long iElem_Surface, iNode_Surface, Point_Surface; + + for (iMarker = 0; iMarker GetnMarker_All(); iMarker++){ + for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { + for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { + + Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); + + node[Point_Surface]->SetPhysicalBoundary(false); + node[Point_Surface]->SetSolidBoundary(false); + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) + node[Point_Surface]->SetPhysicalBoundary(true); + + if (config->GetSolid_Wall(iMarker)) + node[Point_Surface]->SetSolidBoundary(true); + } + } + } + + /*--- Update the normal neighbors ---*/ + + FindNormal_Neighbor(config); + + /*--- Compute wall distance ---- */ + + ComputeWall_Distance(config); + +} + +void CGeometry::SetGeometryPlanes(CConfig *config) { + + bool loop_on; + unsigned short iMarker = 0; + su2double *Face_Normal = NULL, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; + unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; + + /*--- Compute the total number of points on the near-field ---*/ + nVertex_Wall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) + nVertex_Wall += nVertex[iMarker]; + + + /*--- Create an array with all the coordinates, points, pressures, face area, + equivalent area, and nearfield weight ---*/ + Xcoord = new su2double[nVertex_Wall]; + Ycoord = new su2double[nVertex_Wall]; + if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; + FaceArea = new su2double[nVertex_Wall]; + + /*--- Copy the boundary information to an array ---*/ + iVertex_Wall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) + if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || + (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || + (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); + Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); + if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); + Face_Normal = vertex[iMarker][iVertex]->GetNormal(); + FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); + iVertex_Wall ++; + } + + + //vector XCoordList; + vector::iterator IterXCoordList; + + for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) + XCoordList.push_back(Xcoord[iVertex]); + + sort( XCoordList.begin(), XCoordList.end()); + IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); + XCoordList.resize( IterXCoordList - XCoordList.begin() ); + + /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ + Xcoord_plane.resize(XCoordList.size()); + Ycoord_plane.resize(XCoordList.size()); + if (nDim==3) Zcoord_plane.resize(XCoordList.size()); + FaceArea_plane.resize(XCoordList.size()); + Plane_points.resize(XCoordList.size()); + + + su2double dist_ratio; + unsigned long iCoord; + + /*--- Distribute the values among the different PhiAngles ---*/ + for (iPoint = 0; iPoint < nPoint; iPoint++) { + if (node[iPoint]->GetDomain()) { + loop_on = true; + for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { + dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); + if (dist_ratio >= 0 && dist_ratio <= 1.0) { + if (dist_ratio <= 0.5) iCoord = ixCoord; + else iCoord = ixCoord+1; + Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); + Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); + if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); + FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION + Plane_points[iCoord].push_back(iPoint ); + loop_on = false; + } + } + } + } + + /*--- Order the arrays in ascending values of y ---*/ + /// TODO: Depending on the size of the arrays, this may not be a good way of sorting them. + for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) + for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) + for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) + if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { + swap(Xcoord_plane[ixCoord][jVertex], Xcoord_plane[ixCoord][jVertex+1]); + swap(Ycoord_plane[ixCoord][jVertex], Ycoord_plane[ixCoord][jVertex+1]); + if (nDim==3) swap(Zcoord_plane[ixCoord][jVertex], Zcoord_plane[ixCoord][jVertex+1]); + swap(Plane_points[ixCoord][jVertex], Plane_points[ixCoord][jVertex+1]); + swap(FaceArea_plane[ixCoord][jVertex], FaceArea_plane[ixCoord][jVertex+1]); + } + + /*--- Delete structures ---*/ + delete[] Xcoord; delete[] Ycoord; + if (Zcoord != NULL) delete[] Zcoord; + delete[] FaceArea; +} + +void CGeometry::SetRotationalVelocity(CConfig *config, bool print) { + + unsigned long iPoint; + unsigned short iDim; + + su2double RotVel[3] = {0.0,0.0,0.0}, Distance[3] = {0.0,0.0,0.0}, + Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}; + + /*--- Center of rotation & angular velocity vector from config ---*/ + + for (iDim = 0; iDim < nDim; iDim++) { + Center[iDim] = config->GetMotion_Origin(iDim); + Omega[iDim] = config->GetRotation_Rate(iDim)/config->GetOmega_Ref(); + } + + su2double L_Ref = config->GetLength_Ref(); + + /*--- Print some information to the console ---*/ + + if (rank == MASTER_NODE && print) { + cout << " Rotational origin (x, y, z): ( " << Center[0] << ", " << Center[1]; + cout << ", " << Center[2] << " )\n"; + cout << " Angular velocity about x, y, z axes: ( " << Omega[0] << ", "; + cout << Omega[1] << ", " << Omega[2] << " ) rad/s" << endl; + } + + /*--- Loop over all nodes and set the rotational velocity ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Get the coordinates of the current node ---*/ + + const su2double* Coord = node[iPoint]->GetCoord(); + + /*--- Calculate the non-dim. distance from the rotation center ---*/ + + for (iDim = 0; iDim < nDim; iDim++) + Distance[iDim] = (Coord[iDim]-Center[iDim])/L_Ref; + + /*--- Calculate the angular velocity as omega X r ---*/ + + RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); + RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); + RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); + + /*--- Store the grid velocity at this node ---*/ + + node[iPoint]->SetGridVel(RotVel); + + } + +} + +void CGeometry::SetShroudVelocity(CConfig *config) { + + unsigned long iPoint, iVertex; + unsigned short iMarker, iMarkerShroud; + su2double RotVel[3] = {0.0,0.0,0.0}; + + /*--- Loop over all vertex in the shroud marker and set the rotational velocity to 0.0 ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++){ + for(iMarkerShroud=0; iMarkerShroud < config->GetnMarker_Shroud(); iMarkerShroud++){ + if(config->GetMarker_Shroud(iMarkerShroud) == config->GetMarker_All_TagBound(iMarker)){ + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + node[iPoint]->SetGridVel(RotVel); + } + } + } + } +} + +void CGeometry::SetTranslationalVelocity(CConfig *config, bool print) { + + su2double xDot[3] = {0.0,0.0,0.0}; + + /*--- Get the translational velocity vector from config ---*/ + + for (unsigned short iDim = 0; iDim < nDim; iDim++) + xDot[iDim] = config->GetTranslation_Rate(iDim)/config->GetVelocity_Ref(); + + /*--- Print some information to the console ---*/ + + if (rank == MASTER_NODE && print) { + cout << " Non-dim. translational velocity: (" + << xDot[0] << ", " << xDot[1] << ", " << xDot[2] << ")." << endl; + } + + /*--- Loop over all nodes and set the translational velocity ---*/ + + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) + node[iPoint]->SetGridVel(xDot); + +} + +void CGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { + + /*--- Get timestep and whether to use 1st or 2nd order backward finite differences ---*/ + + bool FirstOrder = (config->GetTime_Marching() == DT_STEPPING_1ST); + bool SecondOrder = (config->GetTime_Marching() == DT_STEPPING_2ND); + + su2double TimeStep = config->GetDelta_UnstTimeND(); + + /*--- Compute the velocity of each node in the volume mesh ---*/ + + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { + + /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ + + const su2double *Coord_nM1 = node[iPoint]->GetCoord_n1(); + const su2double *Coord_n = node[iPoint]->GetCoord_n(); + const su2double *Coord_nP1 = node[iPoint]->GetCoord(); + + /*--- Compute and store mesh velocity with 1st or 2nd-order approximation ---*/ + + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + + su2double GridVel = 0.0; + + if (FirstOrder) + GridVel = (Coord_nP1[iDim] - Coord_n[iDim]) / TimeStep; + + if (SecondOrder) + GridVel = (1.5*Coord_nP1[iDim] - 2.0*Coord_n[iDim] + 0.5*Coord_nM1[iDim]) / TimeStep; + + node[iPoint]->SetGridVel(iDim, GridVel); + } + } + +} diff --git a/Common/src/geometry/CMultiGridGeometry.cpp b/Common/src/geometry/CMultiGridGeometry.cpp new file mode 100644 index 000000000000..dd03dcbcd4c9 --- /dev/null +++ b/Common/src/geometry/CMultiGridGeometry.cpp @@ -0,0 +1,1405 @@ +/*! + * \file CMultiGridGeometry.cpp + * \brief Implementation of the multigrid geometry class. + * \author F. Palacios, T. Economon + * \version 7.0.0 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2019, 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/geometry/CMultiGridGeometry.hpp" +#include "../../include/CMultiGridQueue.hpp" +#include "../../include/toolboxes/printing_toolbox.hpp" + + +CMultiGridGeometry::CMultiGridGeometry(CGeometry **geometry, CConfig *config_container, unsigned short iMesh) : CGeometry() { + + /*--- CGeometry & CConfig pointers to the fine grid level for clarity. We may + need access to the other zones in the mesh for zone boundaries. ---*/ + + CGeometry *fine_grid = geometry[iMesh-1]; + CConfig *config = config_container; + + /*--- Local variables ---*/ + + unsigned long iPoint, Index_CoarseCV, CVPoint, iElem, iVertex, jPoint, iteration, nVertexS, nVertexR, + nBufferS_Vector, nBufferR_Vector, iParent, jVertex,Local_nPointCoarse, Local_nPointFine, Global_nPointCoarse, Global_nPointFine, + *Buffer_Receive_Parent = NULL, *Buffer_Send_Parent = NULL, *Buffer_Receive_Children = NULL, *Buffer_Send_Children = NULL, + *Parent_Remote = NULL, *Children_Remote = NULL, *Parent_Local = NULL, *Children_Local = NULL; + short marker_seed; + bool agglomerate_seed = true; + unsigned short nChildren, iNode, counter, iMarker, jMarker, priority, MarkerS, MarkerR, *nChildren_MPI; + vector Suitable_Indirect_Neighbors, Aux_Parent; + vector::iterator it; + + unsigned short nMarker_Max = config->GetnMarker_Max(); + + unsigned short *copy_marker = new unsigned short [nMarker_Max]; + +#ifdef HAVE_MPI + int send_to, receive_from; + SU2_MPI::Status status; +#endif + + nDim = fine_grid->GetnDim(); // Write the number of dimensions of the coarse grid. + + /*--- Create a queue system to deo the agglomeration + 1st) More than two markers ---> Vertices (never agglomerate) + 2nd) Two markers ---> Edges (agglomerate if same BC, never agglomerate if different BC) + 3rd) One marker ---> Surface (always agglomarate) + 4th) No marker ---> Internal Volume (always agglomarate) ---*/ + + /*--- Set a marker to indicate indirect agglomeration ---*/ + + if (iMesh == MESH_1) { + + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) + fine_grid->node[iPoint]->SetAgglomerate_Indirect(false); + + for (iElem = 0; iElem < fine_grid->GetnElem(); iElem++) { + if ((fine_grid->elem[iElem]->GetVTK_Type() == HEXAHEDRON) || + (fine_grid->elem[iElem]->GetVTK_Type() == QUADRILATERAL)) { + for (iNode = 0; iNode < fine_grid->elem[iElem]->GetnNodes(); iNode++) { + iPoint = fine_grid->elem[iElem]->GetNode(iNode); + fine_grid->node[iPoint]->SetAgglomerate_Indirect(true); + } + } + } + + } + + /*--- Create the coarse grid structure using as baseline the fine grid ---*/ + + CMultiGridQueue MGQueue_InnerCV(fine_grid->GetnPoint()); + + nPointNode = fine_grid->GetnPoint(); + node = new CPoint*[fine_grid->GetnPoint()]; + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { + + /*--- Create node structure ---*/ + + node[iPoint] = new CPoint(nDim, iPoint, config); + + /*--- Set the indirect agglomeration to false ---*/ + + node[iPoint]->SetAgglomerate_Indirect(false); + } + + Index_CoarseCV = 0; + + /*--- The first step is the boundary agglomeration. ---*/ + + for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) { + + for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { + iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); + + /*--- If the element has not being previously agglomerated and it belongs + to the physical domain, then the agglomeration is studied ---*/ + + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && + (fine_grid->node[iPoint]->GetDomain()) && + (GeometricalCheck(iPoint, fine_grid, config))) { + + nChildren = 1; + + /*--- We set an index for the parent control volume ---*/ + + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We add the seed point (child) to the parent control volume ---*/ + + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + agglomerate_seed = true; counter = 0; marker_seed = iMarker; + + /*--- For a particular point in the fine grid we save all the markers + that are in that point ---*/ + + for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) + if (fine_grid->node[iPoint]->GetVertex(jMarker) != -1) { + copy_marker[counter] = jMarker; + counter++; + } + + /*--- To aglomerate a vertex it must have only one physical bc!! + This can be improved. If there is only a marker, it is a good + candidate for agglomeration ---*/ + + if (counter == 1) agglomerate_seed = true; + + /*--- If there are two markers, we will aglomerate if one of the + marker is SEND_RECEIVE ---*/ + + if (counter == 2) { + if ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) || + (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) agglomerate_seed = true; + else agglomerate_seed = false; + } + + /*--- If there are more than 2 markers, the aglomeration will be discarted ---*/ + + if (counter > 2) agglomerate_seed = false; + + /*--- If the seed can be agglomerated, we try to agglomerate more points ---*/ + + if (agglomerate_seed) { + + /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ + + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + + CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); + + /*--- The new point can be agglomerated ---*/ + + if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + } + + } + + Suitable_Indirect_Neighbors.clear(); + + if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) + SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); + + /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ + + for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { + + CVPoint = Suitable_Indirect_Neighbors[iNode]; + + /*--- The new point can be agglomerated ---*/ + + if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the indirect agglomeration information ---*/ + + if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) + node[Index_CoarseCV]->SetAgglomerate_Indirect(true); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + } + } + + + } + + /*--- Update the number of child of the control volume ---*/ + + node[Index_CoarseCV]->SetnChildren_CV(nChildren); + Index_CoarseCV++; + } + } + } + + /*--- Agglomerate all the nodes that have more than one physical boundary condition, + Maybe here we can add the posibility of merging the vertex that have the same number, + and kind of markers---*/ + + for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) + for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { + iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && + (fine_grid->node[iPoint]->GetDomain())) { + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + node[Index_CoarseCV]->SetnChildren_CV(1); + Index_CoarseCV++; + } + } + + /*--- Update the queue with the results from the boundary agglomeration ---*/ + + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { + + /*--- The CV has been agglomerated, remove form the list ---*/ + + if (fine_grid->node[iPoint]->GetAgglomerate() == true) { + + MGQueue_InnerCV.RemoveCV(iPoint); + + } + + else { + + /*--- Count the number of agglomerated neighbors, and modify the queue ---*/ + + priority = 0; + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + if (fine_grid->node[jPoint]->GetAgglomerate() == true) priority++; + } + MGQueue_InnerCV.MoveCV(iPoint, priority); + } + } + + /*--- Agglomerate the domain nodes ---*/ + + iteration = 0; + while (!MGQueue_InnerCV.EmptyQueue() && (iteration < fine_grid->GetnPoint())) { + + iPoint = MGQueue_InnerCV.NextCV(); + iteration ++; + + /*--- If the element has not being previously agglomerated, belongs to the physical domain, + and satisfies several geometrical criteria then the seed CV is acepted for agglomeration ---*/ + + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && + (fine_grid->node[iPoint]->GetDomain()) && + (GeometricalCheck(iPoint, fine_grid, config))) { + + nChildren = 1; + + /*--- We set an index for the parent control volume ---*/ + + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We add the seed point (child) to the parent control volume ---*/ + + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + + /*--- Update the queue with the seed point (remove the seed and + increase the priority of the neighbors) ---*/ + + MGQueue_InnerCV.Update(iPoint, fine_grid); + + /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ + + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + + CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); + + /*--- Determine if the CVPoint can be agglomerated ---*/ + + if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && + (fine_grid->node[CVPoint]->GetDomain()) && + (GeometricalCheck(CVPoint, fine_grid, config))) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + + /*--- Update the queue with the new control volume (remove the CV and + increase the priority of the neighbors) ---*/ + + MGQueue_InnerCV.Update(CVPoint, fine_grid); + + } + + } + + /*--- Subrotuine to identify the indirect neighbors ---*/ + + Suitable_Indirect_Neighbors.clear(); + if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) + SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); + + /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ + + for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { + + CVPoint = Suitable_Indirect_Neighbors[iNode]; + + /*--- The new point can be agglomerated ---*/ + + if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && + (fine_grid->node[CVPoint]->GetDomain())) { + + /*--- We set the value of the parent ---*/ + + fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); + + /*--- We set the indirect agglomeration information ---*/ + + if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) + node[Index_CoarseCV]->SetAgglomerate_Indirect(true); + + /*--- We set the value of the child ---*/ + + node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); + nChildren++; + + /*--- Update the queue with the new control volume (remove the CV and + increase the priority of the neighbors) ---*/ + + MGQueue_InnerCV.Update(CVPoint, fine_grid); + + } + } + + /*--- Update the number of control of childrens ---*/ + + node[Index_CoarseCV]->SetnChildren_CV(nChildren); + Index_CoarseCV++; + } + else { + + /*--- The seed point can not be agglomerated because of size, domain, streching, etc. + move the point to the lowest priority ---*/ + + MGQueue_InnerCV.MoveCV(iPoint, -1); + } + + } + + /*--- Add all the elements that have not being agglomerated, in the previous stage ---*/ + + for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { + if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && (fine_grid->node[iPoint]->GetDomain())) { + + nChildren = 1; + fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); + if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) + node[Index_CoarseCV]->SetAgglomerate_Indirect(true); + node[Index_CoarseCV]->SetChildren_CV(0, iPoint); + node[Index_CoarseCV]->SetnChildren_CV(nChildren); + Index_CoarseCV++; + + } + } + + nPointDomain = Index_CoarseCV; + + /*--- Check that there are no hanging nodes ---*/ + + unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iCoarsePoint_Complete; + unsigned short iChildren; + + /*--- Find the point surrounding a point ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { + iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); + iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); + if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); + } + } + } + + /*--- Detect isolated points and merge them with its correct neighbor ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { + + if (node[iCoarsePoint]->GetnPoint() == 1) { + + /*--- Find the neighbor of the isolated point. This neighbor is the right control volume ---*/ + + iCoarsePoint_Complete = node[iCoarsePoint]->GetPoint(0); + + /*--- Add the children to the connected control volume (and modify it parent indexing). + Identify the child CV from the finest grid and added to the correct control volume. + Set the parent CV of iFinePoint. Instead of using the original + (iCoarsePoint) one use the new one (iCoarsePoint_Complete) ---*/ + + nChildren = node[iCoarsePoint_Complete]->GetnChildren_CV(); + + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + node[iCoarsePoint_Complete]->SetChildren_CV(nChildren, iFinePoint); + nChildren++; + fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint_Complete); + } + + /*--- Update the number of children control volumes ---*/ + + node[iCoarsePoint_Complete]->SetnChildren_CV(nChildren); + node[iCoarsePoint]->SetnChildren_CV(0); + + } + } + + // unsigned long iPointFree = nPointDomain-1; + // iCoarsePoint = 0; + // + // do { + // + // if (node[iCoarsePoint]->GetnChildren_CV() == 0) { + // + // while (node[iPointFree]->GetnChildren_CV() == 0) { + // Index_CoarseCV--; + // iPointFree--; + // } + // + // nChildren = node[iPointFree]->GetnChildren_CV(); + // for (iChildren = 0; iChildren < nChildren; iChildren ++) { + // iFinePoint = node[iPointFree]->GetChildren_CV(iChildren); + // node[iCoarsePoint]->SetChildren_CV(iChildren, iFinePoint); + // fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint); + // } + // node[iCoarsePoint]->SetnChildren_CV(nChildren); + // node[iPointFree]->SetnChildren_CV(0); + // + // Index_CoarseCV--; + // iPointFree--; + // + // } + // + // iCoarsePoint++; + // + // } while ((iCoarsePoint-1) < Index_CoarseCV); + // + // nPointDomain = Index_CoarseCV; + + /*--- Reset the point surrounding a point ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { + node[iCoarsePoint]->ResetPoint(); + } + + /*--- Dealing with MPI parallelization, the objective is that the received nodes must be agglomerated + in the same way as the donor nodes. Send the node agglomeration information of the donor + (parent and children), Sending only occurs with MPI ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && + (config->GetMarker_All_SendRecv(iMarker) > 0)) { + + MarkerS = iMarker; MarkerR = iMarker+1; + +#ifdef HAVE_MPI + send_to = config->GetMarker_All_SendRecv(MarkerS)-1; + receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; +#endif + + nVertexS = fine_grid->nVertex[MarkerS]; nVertexR = fine_grid->nVertex[MarkerR]; + nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; + + /*--- Allocate Receive and send buffers ---*/ + + Buffer_Receive_Children = new unsigned long [nBufferR_Vector]; + Buffer_Send_Children = new unsigned long [nBufferS_Vector]; + + Buffer_Receive_Parent = new unsigned long [nBufferR_Vector]; + Buffer_Send_Parent = new unsigned long [nBufferS_Vector]; + + /*--- Copy the information that should be sended ---*/ + + for (iVertex = 0; iVertex < nVertexS; iVertex++) { + iPoint = fine_grid->vertex[MarkerS][iVertex]->GetNode(); + Buffer_Send_Children[iVertex] = iPoint; + Buffer_Send_Parent[iVertex] = fine_grid->node[iPoint]->GetParent_CV(); + } + +#ifdef HAVE_MPI + /*--- Send/Receive information using Sendrecv ---*/ + SU2_MPI::Sendrecv(Buffer_Send_Children, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,0, + Buffer_Receive_Children, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,0, MPI_COMM_WORLD, &status); + SU2_MPI::Sendrecv(Buffer_Send_Parent, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,1, + Buffer_Receive_Parent, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,1, MPI_COMM_WORLD, &status); +#else + /*--- Receive information without MPI ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + Buffer_Receive_Children[iVertex] = Buffer_Send_Children[iVertex]; + Buffer_Receive_Parent[iVertex] = Buffer_Send_Parent[iVertex]; + } +#endif + + /*--- Deallocate send buffer ---*/ + + delete [] Buffer_Send_Children; + delete [] Buffer_Send_Parent; + + /*--- Create a list of the parent nodes without repeated parents ---*/ + + Aux_Parent.clear(); + for (iVertex = 0; iVertex < nVertexR; iVertex++) + Aux_Parent.push_back (Buffer_Receive_Parent[iVertex]); + + sort(Aux_Parent.begin(), Aux_Parent.end()); + it = unique(Aux_Parent.begin(), Aux_Parent.end()); + Aux_Parent.resize(it - Aux_Parent.begin()); + + /*--- Allocate some structures ---*/ + + Parent_Remote = new unsigned long[nVertexR]; + Children_Remote = new unsigned long[nVertexR]; + Parent_Local = new unsigned long[nVertexR]; + Children_Local = new unsigned long[nVertexR]; + + /*--- Create the local vector and remote for the parents and the children ---*/ + + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + Parent_Remote[iVertex] = Buffer_Receive_Parent[iVertex]; + + /*--- We use the same sorting as in the donor domain ---*/ + + for (jVertex = 0; jVertex < Aux_Parent.size(); jVertex++) { + if (Parent_Remote[iVertex] == Aux_Parent[jVertex]) { + Parent_Local[iVertex] = jVertex + Index_CoarseCV; + break; + } + } + + Children_Remote[iVertex] = Buffer_Receive_Children[iVertex]; + Children_Local[iVertex] = fine_grid->vertex[MarkerR][iVertex]->GetNode(); + + } + + Index_CoarseCV += Aux_Parent.size(); + + nChildren_MPI = new unsigned short [Index_CoarseCV]; + for (iParent = 0; iParent < Index_CoarseCV; iParent++) + nChildren_MPI[iParent] = 0; + + /*--- Create the final structure ---*/ + for (iVertex = 0; iVertex < nVertexR; iVertex++) { + + /*--- Be careful, it is possible that a node change the agglomeration configuration, the priority + is always, when receive the information ---*/ + + fine_grid->node[Children_Local[iVertex]]->SetParent_CV(Parent_Local[iVertex]); + node[Parent_Local[iVertex]]->SetChildren_CV(nChildren_MPI[Parent_Local[iVertex]], Children_Local[iVertex]); + nChildren_MPI[Parent_Local[iVertex]]++; + node[Parent_Local[iVertex]]->SetnChildren_CV(nChildren_MPI[Parent_Local[iVertex]]); + node[Parent_Local[iVertex]]->SetDomain(false); + + } + + /*--- Deallocate auxiliar structures ---*/ + + delete[] nChildren_MPI; + delete[] Parent_Remote; + delete[] Children_Remote; + delete[] Parent_Local; + delete[] Children_Local; + + /*--- Deallocate receive buffer ---*/ + + delete [] Buffer_Receive_Children; + delete [] Buffer_Receive_Parent; + + } + + } + + /*--- Update the number of points after the MPI agglomeration ---*/ + + nPoint = Index_CoarseCV; + + /*--- Console output with the summary of the agglomeration ---*/ + + Local_nPointCoarse = nPoint; + Local_nPointFine = fine_grid->GetnPoint(); + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&Local_nPointCoarse, &Global_nPointCoarse, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); + SU2_MPI::Allreduce(&Local_nPointFine, &Global_nPointFine, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); +#else + Global_nPointCoarse = Local_nPointCoarse; + Global_nPointFine = Local_nPointFine; +#endif + + su2double Coeff = 1.0, CFL = 0.0, factor = 1.5; + + if (iMesh != MESH_0) { + if (nDim == 2) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./2.); + if (nDim == 3) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./3.); + CFL = factor*config->GetCFL(iMesh-1)/Coeff; + config->SetCFL(iMesh, CFL); + } + + su2double ratio = su2double(Global_nPointFine)/su2double(Global_nPointCoarse); + + if (((nDim == 2) && (ratio < 2.5)) || + ((nDim == 3) && (ratio < 2.5))) { + config->SetMGLevels(iMesh-1); + } + else { + if (rank == MASTER_NODE) { + PrintingToolbox::CTablePrinter MGTable(&std::cout); + MGTable.AddColumn("MG Level", 10); + MGTable.AddColumn("CVs", 10); + MGTable.AddColumn("Aggl. Rate", 10); + MGTable.AddColumn("CFL", 10); + MGTable.SetAlign(PrintingToolbox::CTablePrinter::RIGHT); + + + if (iMesh == 1){ + MGTable.PrintHeader(); + MGTable << iMesh - 1 << Global_nPointFine << "1/1.00" << config->GetCFL(iMesh -1); + } + stringstream ss; + ss << "1/" << std::setprecision(3) << ratio; + MGTable << iMesh << Global_nPointCoarse << ss.str() << CFL; + if (iMesh == config->GetnMGLevels()){ + MGTable.PrintFooter(); + } + } + } + + delete [] copy_marker; + +} + + +CMultiGridGeometry::~CMultiGridGeometry(void) { + +} + +bool CMultiGridGeometry::SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config) { + + bool agglomerate_CV = false; + unsigned short counter, jMarker; + + unsigned short nMarker_Max = config->GetnMarker_Max(); + + unsigned short *copy_marker = new unsigned short [nMarker_Max]; + + /*--- Basic condition, the element has not being previously agglomerated, it belongs to the domain, + and has passed some basic geometrical check ---*/ + + if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && + (fine_grid->node[CVPoint]->GetDomain()) && + (GeometricalCheck(CVPoint, fine_grid, config))) { + + /*--- If the element belong to the boundary, we must be careful ---*/ + + if (fine_grid->node[CVPoint]->GetBoundary()) { + + /*--- Identify the markers of the vertex that we want to agglomerate ---*/ + + counter = 0; + for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) + if (fine_grid->node[CVPoint]->GetVertex(jMarker) != -1) { + copy_marker[counter] = jMarker; + counter++; + } + + /*--- The basic condition is that the aglomerated vertex must have the same physical marker, + but eventually a send-receive condition ---*/ + + /*--- Only one marker in the vertex that is going to be aglomerated ---*/ + + if (counter == 1) { + + /*--- We agglomerate if there is only a marker and is the same marker as the seed marker ---*/ + + if (copy_marker[0] == marker_seed) + agglomerate_CV = true; + + /*--- If there is only a marker, but the marker is the SEND_RECEIVE ---*/ + + if (config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) + agglomerate_CV = true; + + } + + /*--- If there are two markers in the vertex that is going to be aglomerated ---*/ + + if (counter == 2) { + + /*--- First we verify that the seed is a physical boundary ---*/ + + if (config->GetMarker_All_KindBC(marker_seed) != SEND_RECEIVE) { + + /*--- Then we check that one of the marker is equal to the seed marker, and the other is send/receive ---*/ + + if (((copy_marker[0] == marker_seed) && (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) || + ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) && (copy_marker[1] == marker_seed))) + agglomerate_CV = true; + } + + } + + } + + /*--- If the element belong to the domain, it is allways aglomerated ---*/ + + else { agglomerate_CV = true; } + + } + + delete [] copy_marker; + + return agglomerate_CV; + +} + + +bool CMultiGridGeometry::GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config) { + + su2double max_dimension = 1.2; + + /*--- Evaluate the total size of the element ---*/ + + bool Volume = true; + su2double ratio = pow(fine_grid->node[iPoint]->GetVolume(), 1.0/su2double(nDim))*max_dimension; + su2double limit = pow(config->GetDomainVolume(), 1.0/su2double(nDim)); + if ( ratio > limit ) Volume = false; + + /*--- Evaluate the stretching of the element ---*/ + + bool Stretching = true; + + /* unsigned short iNode, iDim; + unsigned long jPoint; + su2double *Coord_i = fine_grid->node[iPoint]->GetCoord(); + su2double max_dist = 0.0 ; su2double min_dist = 1E20; + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + su2double *Coord_j = fine_grid->node[jPoint]->GetCoord(); + su2double distance = 0.0; + for (iDim = 0; iDim < nDim; iDim++) + distance += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); + distance = sqrt(distance); + max_dist = max(distance, max_dist); + min_dist = min(distance, min_dist); + } + if ( max_dist/min_dist > 100.0 ) Stretching = false;*/ + + return (Stretching && Volume); + +} + +void CMultiGridGeometry::SetSuitableNeighbors(vector *Suitable_Indirect_Neighbors, unsigned long iPoint, + unsigned long Index_CoarseCV, CGeometry *fine_grid) { + + unsigned long jPoint, kPoint, lPoint; + unsigned short iNode, jNode, iNeighbor, jNeighbor, kNode; + bool SecondNeighborSeed, ThirdNeighborSeed; + vector::iterator it; + + /*--- Create a list with the first neighbors, including the seed ---*/ + + vector First_Neighbor_Points; + First_Neighbor_Points.push_back(iPoint); + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + First_Neighbor_Points.push_back(jPoint); + } + + /*--- Create a list with the second neighbors, without first, and seed neighbors ---*/ + + vector Second_Neighbor_Points, Second_Origin_Points, Suitable_Second_Neighbors; + + for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { + jPoint = fine_grid->node[iPoint]->GetPoint(iNode); + + for (jNode = 0; jNode < fine_grid->node[jPoint]->GetnPoint(); jNode ++) { + kPoint = fine_grid->node[jPoint]->GetPoint(jNode); + + /*--- Check that the second neighbor do not belong to the first neighbor or the seed ---*/ + + SecondNeighborSeed = true; + for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) + if (kPoint == First_Neighbor_Points[iNeighbor]) { + SecondNeighborSeed = false; break; + } + + if (SecondNeighborSeed) { + Second_Neighbor_Points.push_back(kPoint); + Second_Origin_Points.push_back(jPoint); + } + + } + } + + /*--- Identify those second neighbors that are repeated (candidate to be added) ---*/ + + for (iNeighbor = 0; iNeighbor < Second_Neighbor_Points.size(); iNeighbor ++) + + for (jNeighbor = 0; jNeighbor < Second_Neighbor_Points.size(); jNeighbor ++) + + /*--- Repeated second neighbor with different origin ---*/ + + if ((Second_Neighbor_Points[iNeighbor] == Second_Neighbor_Points[jNeighbor]) && + (Second_Origin_Points[iNeighbor] != Second_Origin_Points[jNeighbor]) && + (iNeighbor < jNeighbor)) { + + Suitable_Indirect_Neighbors->push_back(Second_Neighbor_Points[iNeighbor]); + + /*--- Create alist with the suitable second neighbor, that we will use + to compute the third neighbors --*/ + + Suitable_Second_Neighbors.push_back(Second_Neighbor_Points[iNeighbor]); + + } + + + /*--- Remove repeated from the suitable second neighbors ---*/ + + sort(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); + it = unique(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); + Suitable_Second_Neighbors.resize(it - Suitable_Second_Neighbors.begin()); + + /*--- Remove repeated from first neighbors ---*/ + + sort(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); + it = unique(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); + First_Neighbor_Points.resize(it - First_Neighbor_Points.begin()); + + /*--- Create a list with the third neighbors, without first, second, and seed neighbors ---*/ + + vector Third_Neighbor_Points, Third_Origin_Points; + + for (jNode = 0; jNode < Suitable_Second_Neighbors.size(); jNode ++) { + kPoint = Suitable_Second_Neighbors[jNode]; + + for (kNode = 0; kNode < fine_grid->node[kPoint]->GetnPoint(); kNode ++) { + lPoint = fine_grid->node[kPoint]->GetPoint(kNode); + + /*--- Check that the third neighbor do not belong to the first neighbors or the seed ---*/ + + ThirdNeighborSeed = true; + + for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) + if (lPoint == First_Neighbor_Points[iNeighbor]) { + ThirdNeighborSeed = false; + break; + } + + /*--- Check that the third neighbor do not belong to the second neighbors ---*/ + + for (iNeighbor = 0; iNeighbor < Suitable_Second_Neighbors.size(); iNeighbor ++) + if (lPoint == Suitable_Second_Neighbors[iNeighbor]) { + ThirdNeighborSeed = false; + break; + } + + if (ThirdNeighborSeed) { + Third_Neighbor_Points.push_back(lPoint); + Third_Origin_Points.push_back(kPoint); + } + + } + } + + /*--- Identify those third neighbors that are repeated (candidate to be added) ---*/ + + for (iNeighbor = 0; iNeighbor < Third_Neighbor_Points.size(); iNeighbor ++) + for (jNeighbor = 0; jNeighbor < Third_Neighbor_Points.size(); jNeighbor ++) + + /*--- Repeated second neighbor with different origin ---*/ + + if ((Third_Neighbor_Points[iNeighbor] == Third_Neighbor_Points[jNeighbor]) && + (Third_Origin_Points[iNeighbor] != Third_Origin_Points[jNeighbor]) && + (iNeighbor < jNeighbor)) { + + Suitable_Indirect_Neighbors->push_back(Third_Neighbor_Points[iNeighbor]); + + } + + /*--- Remove repeated from Suitable Indirect Neighbors List ---*/ + + sort(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); + it = unique(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); + Suitable_Indirect_Neighbors->resize(it - Suitable_Indirect_Neighbors->begin()); + +} + +void CMultiGridGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { + + unsigned long iFinePoint, iFinePoint_Neighbor, iParent, iCoarsePoint; + unsigned short iChildren, iNode; + + /*--- Set the point surrounding a point ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { + iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); + iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); + if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); + } + } + } + + /*--- Set the number of neighbors variable, this is + important for JST and multigrid in parallel ---*/ + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + node[iCoarsePoint]->SetnNeighbor(node[iCoarsePoint]->GetnPoint()); + +} + +void CMultiGridGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { + unsigned long iVertex, iFinePoint, iCoarsePoint; + unsigned short iMarker, iMarker_Tag, iChildren; + + nMarker = fine_grid->GetnMarker(); + unsigned short nMarker_Max = config->GetnMarker_Max(); + + /*--- If any children node belong to the boundary then the entire control + volume will belong to the boundary ---*/ + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + if (fine_grid->node[iFinePoint]->GetBoundary()) { + node[iCoarsePoint]->SetBoundary(nMarker); + break; + } + } + + vertex = new CVertex**[nMarker]; + nVertex = new unsigned long [nMarker]; + + Tag_to_Marker = new string [nMarker_Max]; + for (iMarker_Tag = 0; iMarker_Tag < nMarker_Max; iMarker_Tag++) + Tag_to_Marker[iMarker_Tag] = fine_grid->GetMarker_Tag(iMarker_Tag); + + /*--- Compute the number of vertices to do the dimensionalization ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; + + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + if (node[iCoarsePoint]->GetBoundary()) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iMarker = 0; iMarker < nMarker; iMarker ++) { + if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { + iVertex = nVertex[iMarker]; + node[iCoarsePoint]->SetVertex(iVertex, iMarker); + nVertex[iMarker]++; + } + } + } + } + } + + for (iMarker = 0; iMarker < nMarker; iMarker++) { + vertex[iMarker] = new CVertex* [fine_grid->GetnVertex(iMarker)+1]; + nVertex[iMarker] = 0; + } + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + if (node[iCoarsePoint]->GetBoundary()) + for (iMarker = 0; iMarker < nMarker; iMarker ++) + node[iCoarsePoint]->SetVertex(-1, iMarker); + + for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + if (node[iCoarsePoint]->GetBoundary()) { + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker ++) { + if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { + iVertex = nVertex[iMarker]; + vertex[iMarker][iVertex] = new CVertex(iCoarsePoint, nDim); + node[iCoarsePoint]->SetVertex(iVertex, iMarker); + + /*--- Set the transformation to apply ---*/ + unsigned long ChildVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); + unsigned short RotationKind = fine_grid->vertex[iMarker][ChildVertex]->GetRotation_Type(); + vertex[iMarker][iVertex]->SetRotation_Type(RotationKind); + nVertex[iMarker]++; + } + } + } + } + } +} + +void CMultiGridGeometry::MatchNearField(CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex, iPoint; + int iProcessor = size; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor); + } + } + } + } + +} + +void CMultiGridGeometry::MatchActuator_Disk(CConfig *config) { + + unsigned short iMarker; + unsigned long iVertex, iPoint; + int iProcessor = size; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || + (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor); + } + } + } + } + +} + +void CMultiGridGeometry::MatchPeriodic(CConfig *config, unsigned short val_periodic) { + + unsigned short iMarker, iPeriodic, nPeriodic; + unsigned long iVertex, iPoint; + int iProcessor = rank; + + /*--- Evaluate the number of periodic boundary conditions ---*/ + + nPeriodic = config->GetnMarker_Periodic(); + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { + iPeriodic = config->GetMarker_All_PerBound(iMarker); + if ((iPeriodic == val_periodic) || + (iPeriodic == val_periodic + nPeriodic/2)) { + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iPoint = vertex[iMarker][iVertex]->GetNode(); + if (node[iPoint]->GetDomain()) { + vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor); + } + } + } + } + } + +} + +void CMultiGridGeometry::SetControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { + + unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iEdge, iParent; + long FineEdge, CoarseEdge; + unsigned short iChildren, iNode, iDim; + bool change_face_orientation; + su2double *Normal, Coarse_Volume, Area, *NormalFace = NULL; + Normal = new su2double [nDim]; + + /*--- Compute the area of the coarse volume ---*/ + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { + node[iCoarsePoint]->SetVolume(0.0); + Coarse_Volume = 0.0; + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + Coarse_Volume += fine_grid->node[iFinePoint]->GetVolume(); + } + node[iCoarsePoint]->SetVolume(Coarse_Volume); + } + + /*--- Update or not the values of faces at the edge ---*/ + if (action != ALLOCATE) { + for (iEdge=0; iEdge < nEdge; iEdge++) + edge[iEdge]->SetZeroValues(); + } + + for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + + for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { + iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); + iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); + if ((iParent != iCoarsePoint) && (iParent < iCoarsePoint)) { + + FineEdge = fine_grid->FindEdge(iFinePoint, iFinePoint_Neighbor); + + change_face_orientation = false; + if (iFinePoint < iFinePoint_Neighbor) change_face_orientation = true; + + CoarseEdge = FindEdge(iParent, iCoarsePoint); + + fine_grid->edge[FineEdge]->GetNormal(Normal); + + if (change_face_orientation) { + for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; + edge[CoarseEdge]->AddNormal(Normal); + } + else { + edge[CoarseEdge]->AddNormal(Normal); + } + } + } + } + delete[] Normal; + + /*--- Check if there is a normal with null area ---*/ + + for (iEdge = 0; iEdge < nEdge; iEdge++) { + NormalFace = edge[iEdge]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; + Area = sqrt(Area); + if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; + } + +} + +void CMultiGridGeometry::SetBoundControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { + unsigned long iCoarsePoint, iFinePoint, FineVertex, iVertex; + unsigned short iMarker, iChildren, iDim; + su2double *Normal, Area, *NormalFace = NULL; + + Normal = new su2double [nDim]; + + if (action != ALLOCATE) { + for (iMarker = 0; iMarker < nMarker; iMarker++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) + vertex[iMarker][iVertex]->SetZeroValues(); + } + + for (iMarker = 0; iMarker < nMarker; iMarker ++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + iCoarsePoint = vertex[iMarker][iVertex]->GetNode(); + for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { + iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); + if (fine_grid->node[iFinePoint]->GetVertex(iMarker)!=-1) { + FineVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); + fine_grid->vertex[iMarker][FineVertex]->GetNormal(Normal); + vertex[iMarker][iVertex]->AddNormal(Normal); + } + } + } + + delete[] Normal; + + /*--- Check if there is a normal with null area ---*/ + for (iMarker = 0; iMarker < nMarker; iMarker ++) + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + NormalFace = vertex[iMarker][iVertex]->GetNormal(); + Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; + Area = sqrt(Area); + if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; + } + +} + +void CMultiGridGeometry::SetCoord(CGeometry *geometry) { + unsigned long Point_Fine, Point_Coarse; + unsigned short iChildren, iDim; + su2double Area_Parent, Area_Children; + su2double *Coordinates_Fine, *Coordinates; + Coordinates = new su2double[nDim]; + + for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { + Area_Parent = node[Point_Coarse]->GetVolume(); + for (iDim = 0; iDim < nDim; iDim++) Coordinates[iDim] = 0.0; + for (iChildren = 0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++) { + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); + Area_Children = geometry->node[Point_Fine]->GetVolume(); + Coordinates_Fine = geometry->node[Point_Fine]->GetCoord(); + for (iDim = 0; iDim < nDim; iDim++) + Coordinates[iDim] += Coordinates_Fine[iDim]*Area_Children/Area_Parent; + } + for (iDim = 0; iDim < nDim; iDim++) + node[Point_Coarse]->SetCoord(iDim, Coordinates[iDim]); + } + delete[] Coordinates; +} + +void CMultiGridGeometry::SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker){ + + unsigned long Point_Fine, Point_Coarse, iVertex; + unsigned short iChildren; + long Vertex_Fine; + su2double Area_Parent, Area_Children; + su2double WallHeatFlux_Fine, WallHeatFlux_Coarse; + bool isVertex; + int numberVertexChildren; + + for(iVertex=0; iVertex < nVertex[val_marker]; iVertex++){ + Point_Coarse = vertex[val_marker][iVertex]->GetNode(); + if (node[Point_Coarse]->GetDomain()){ + Area_Parent = 0.0; + WallHeatFlux_Coarse = 0.0; + numberVertexChildren = 0; + /*--- Compute area parent by taking into account only volumes that are on the marker ---*/ + for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); + isVertex = (node[Point_Fine]->GetDomain() && geometry->node[Point_Fine]->GetVertex(val_marker) != -1); + if (isVertex){ + numberVertexChildren += 1; + Area_Parent += geometry->node[Point_Fine]->GetVolume(); + } + } + + /*--- Loop again and propagate values to the coarser level ---*/ + for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); + Vertex_Fine = geometry->node[Point_Fine]->GetVertex(val_marker); + isVertex = (node[Point_Fine]->GetDomain() && Vertex_Fine != -1); + if(isVertex){ + Area_Children = geometry->node[Point_Fine]->GetVolume(); + //Get the customized BC values on fine level and compute the values at coarse level + WallHeatFlux_Fine = geometry->GetCustomBoundaryHeatFlux(val_marker, Vertex_Fine); + WallHeatFlux_Coarse += WallHeatFlux_Fine*Area_Children/Area_Parent; + } + + } + //Set the customized BC values at coarse level + CustomBoundaryHeatFlux[val_marker][iVertex] = WallHeatFlux_Coarse; + } + } + +} + +void CMultiGridGeometry::SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker){ + + unsigned long Point_Fine, Point_Coarse, iVertex; + unsigned short iChildren; + long Vertex_Fine; + su2double Area_Parent, Area_Children; + su2double WallTemperature_Fine, WallTemperature_Coarse; + bool isVertex; + int numberVertexChildren; + + for(iVertex=0; iVertex < nVertex[val_marker]; iVertex++){ + Point_Coarse = vertex[val_marker][iVertex]->GetNode(); + if (node[Point_Coarse]->GetDomain()){ + Area_Parent = 0.0; + WallTemperature_Coarse = 0.0; + numberVertexChildren = 0; + /*--- Compute area parent by taking into account only volumes that are on the marker ---*/ + for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); + isVertex = (node[Point_Fine]->GetDomain() && geometry->node[Point_Fine]->GetVertex(val_marker) != -1); + if (isVertex){ + numberVertexChildren += 1; + Area_Parent += geometry->node[Point_Fine]->GetVolume(); + } + } + + /*--- Loop again and propagate values to the coarser level ---*/ + for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); + Vertex_Fine = geometry->node[Point_Fine]->GetVertex(val_marker); + isVertex = (node[Point_Fine]->GetDomain() && Vertex_Fine != -1); + if(isVertex){ + Area_Children = geometry->node[Point_Fine]->GetVolume(); + //Get the customized BC values on fine level and compute the values at coarse level + WallTemperature_Fine = geometry->GetCustomBoundaryTemperature(val_marker, Vertex_Fine); + WallTemperature_Coarse += WallTemperature_Fine*Area_Children/Area_Parent; + } + + } + //Set the customized BC values at coarse level + CustomBoundaryTemperature[val_marker][iVertex] = WallTemperature_Coarse; + } + } + +} + +void CMultiGridGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { + + /*--- Local variables ---*/ + unsigned short iDim, iChild; + unsigned long Point_Coarse, Point_Fine; + su2double Area_Parent, Area_Child, Grid_Vel[3], *Grid_Vel_Fine; + + /*--- Loop over all coarse mesh points ---*/ + for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { + Area_Parent = node[Point_Coarse]->GetVolume(); + + /*--- Zero out the grid velocity ---*/ + for (iDim = 0; iDim < nDim; iDim++) + Grid_Vel[iDim] = 0.0; + + /*--- Loop over all of the children for this coarse CV and compute + a grid velocity based on the values in the child CVs (fine mesh). ---*/ + for (iChild = 0; iChild < node[Point_Coarse]->GetnChildren_CV(); iChild++) { + Point_Fine = node[Point_Coarse]->GetChildren_CV(iChild); + Area_Child = fine_mesh->node[Point_Fine]->GetVolume(); + Grid_Vel_Fine = fine_mesh->node[Point_Fine]->GetGridVel(); + for (iDim = 0; iDim < nDim; iDim++) + Grid_Vel[iDim] += Grid_Vel_Fine[iDim]*Area_Child/Area_Parent; + } + + /*--- Set the grid velocity for this coarse node. ---*/ + for (iDim = 0; iDim < nDim; iDim++) + node[Point_Coarse]->SetGridVel(iDim, Grid_Vel[iDim]); + } +} + + +void CMultiGridGeometry::FindNormal_Neighbor(CConfig *config) { + + unsigned short iMarker, iDim; + unsigned long iPoint, iVertex; + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && + config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && + config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { + + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { + + iPoint = vertex[iMarker][iVertex]->GetNode(); + + /*--- If the node belong to the domain ---*/ + if (node[iPoint]->GetDomain()) { + + /*--- Compute closest normal neighbor ---*/ + su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord; + unsigned long Point_Normal = 0, jPoint; + unsigned short iNeigh; + su2double *Normal = vertex[iMarker][iVertex]->GetNormal(); + cos_max = -1.0; + for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { + jPoint = node[iPoint]->GetPoint(iNeigh); + scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim); + scalar_prod += diff_coord*Normal[iDim]; + norm_vect += diff_coord*diff_coord; + norm_Normal += Normal[iDim]*Normal[iDim]; + } + norm_vect = sqrt(norm_vect); + norm_Normal = sqrt(norm_Normal); + cos_alpha = scalar_prod/(norm_vect*norm_Normal); + + /*--- Get maximum cosine (not minimum because normals are oriented inwards) ---*/ + if (cos_alpha >= cos_max) { + Point_Normal = jPoint; + cos_max = cos_alpha; + } + } + vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal); + } + } + } + } +} + diff --git a/Common/src/geometry_structure.cpp b/Common/src/geometry/CPhysicalGeometry.cpp similarity index 65% rename from Common/src/geometry_structure.cpp rename to Common/src/geometry/CPhysicalGeometry.cpp index 18e8b6a13766..09e77e66ff58 100644 --- a/Common/src/geometry_structure.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -1,6 +1,6 @@ /*! - * \file geometry_structure.cpp - * \brief Main subroutines for creating the primal grid and multigrid structure. + * \file CPhysicalGeometry.cpp + * \brief Implementation of the physical geometry class. * \author F. Palacios, T. Economon * \version 7.0.0 "Blackbird" * @@ -25,3737 +25,27 @@ * License along with SU2. If not, see . */ -#include "../include/geometry_structure.hpp" -#include "../include/adt_structure.hpp" -#include "../include/toolboxes/printing_toolbox.hpp" -#include "../include/toolboxes/CLinearPartitioner.hpp" -#include "../include/geometry/elements/CElement.hpp" -#include "../include/CSU2ASCIIMeshReaderFVM.hpp" -#include "../include/CCGNSMeshReaderFVM.hpp" -#include "../include/CRectangularMeshReaderFVM.hpp" -#include "../include/CBoxMeshReaderFVM.hpp" -#include "../include/CMultiGridQueue.hpp" -#include -#include -#include -#include -#ifdef _MSC_VER -#include -#endif - -/*--- Epsilon definition ---*/ - -#define EPSILON 0.000001 - -/*--- Cross product ---*/ - -#define CROSS(dest,v1,v2) \ -(dest)[0] = (v1)[1]*(v2)[2] - (v1)[2]*(v2)[1]; \ -(dest)[1] = (v1)[2]*(v2)[0] - (v1)[0]*(v2)[2]; \ -(dest)[2] = (v1)[0]*(v2)[1] - (v1)[1]*(v2)[0]; - -/*--- Cross product ---*/ - -#define DOT(v1,v2) ((v1)[0]*(v2)[0] + (v1)[1]*(v2)[1] + (v1)[2]*(v2)[2]); - -/*--- a = b - c ---*/ - -#define SUB(dest,v1,v2) \ -(dest)[0] = (v1)[0] - (v2)[0]; \ -(dest)[1] = (v1)[1] - (v2)[1]; \ -(dest)[2] = (v1)[2] - (v2)[2]; - -CGeometry::CGeometry(void) { - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - nEdge = 0; - nPoint = 0; - nPointNode = 0; - nElem = 0; - - nElem_Bound = NULL; - Tag_to_Marker = NULL; - elem = NULL; - face = NULL; - bound = NULL; - node = NULL; - edge = NULL; - vertex = NULL; - nVertex = NULL; - newBound = NULL; - nNewElem_Bound = NULL; - Marker_All_SendRecv = NULL; - - XCoordList.clear(); - Xcoord_plane.clear(); - Ycoord_plane.clear(); - Zcoord_plane.clear(); - FaceArea_plane.clear(); - Plane_points.clear(); - - /*--- Arrays for defining the linear partitioning ---*/ - - beg_node = NULL; - end_node = NULL; - - nPointLinear = NULL; - nPointCumulative = NULL; - - /*--- Containers for customized boundary conditions ---*/ - - CustomBoundaryHeatFlux = NULL; //Customized heat flux wall - CustomBoundaryTemperature = NULL; //Customized temperature wall - - /*--- MPI point-to-point data structures ---*/ - - nP2PSend = 0; - nP2PRecv = 0; - - countPerPoint = 0; - - bufD_P2PSend = NULL; - bufD_P2PRecv = NULL; - - bufS_P2PSend = NULL; - bufS_P2PRecv = NULL; - - req_P2PSend = NULL; - req_P2PRecv = NULL; - - nPoint_P2PSend = NULL; - nPoint_P2PRecv = NULL; - - Neighbors_P2PSend = NULL; - Neighbors_P2PRecv = NULL; - - Local_Point_P2PSend = NULL; - Local_Point_P2PRecv = NULL; - - /*--- MPI periodic data structures ---*/ - - nPeriodicSend = 0; - nPeriodicRecv = 0; - - countPerPeriodicPoint = 0; - - bufD_PeriodicSend = NULL; - bufD_PeriodicRecv = NULL; - - bufS_PeriodicSend = NULL; - bufS_PeriodicRecv = NULL; - - req_PeriodicSend = NULL; - req_PeriodicRecv = NULL; - - nPoint_PeriodicSend = NULL; - nPoint_PeriodicRecv = NULL; - - Neighbors_PeriodicSend = NULL; - Neighbors_PeriodicRecv = NULL; - - Local_Point_PeriodicSend = NULL; - Local_Point_PeriodicRecv = NULL; - - Local_Marker_PeriodicSend = NULL; - Local_Marker_PeriodicRecv = NULL; - -} - -CGeometry::~CGeometry(void) { - - unsigned long iElem, iElem_Bound, iEdge, iFace, iPoint, iVertex; - unsigned short iMarker; - - if (elem != NULL) { - for (iElem = 0; iElem < nElem; iElem++) - if (elem[iElem] != NULL) delete elem[iElem]; - delete[] elem; - } - - if (bound != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound]; - } - if (bound[iMarker] != NULL) delete [] bound[iMarker]; - } - delete [] bound; - } - - if (face != NULL) { - for (iFace = 0; iFace < nFace; iFace ++) - if (face[iFace] != NULL) delete face[iFace]; - delete[] face; - } - - if (node != NULL) { - for (iPoint = 0; iPoint < nPointNode; iPoint ++) - if (node[iPoint] != NULL) delete node[iPoint]; - delete[] node; - } - - - if (edge != NULL) { - for (iEdge = 0; iEdge < nEdge; iEdge ++) - if (edge[iEdge] != NULL) delete edge[iEdge]; - delete[] edge; - } - - if (vertex != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - if (vertex[iMarker][iVertex] != NULL) delete vertex[iMarker][iVertex]; - } - if (vertex[iMarker] != NULL) delete [] vertex[iMarker]; - } - delete [] vertex; - } - - if (newBound != NULL) { - for (iMarker = 0; iMarker < nMarker; iMarker++) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (newBound[iMarker][iElem_Bound] != NULL) delete [] newBound[iMarker][iElem_Bound]; - } - delete[] newBound[iMarker]; - } - delete[] newBound; - } - - if (nElem_Bound != NULL) delete [] nElem_Bound; - if (nVertex != NULL) delete [] nVertex; - if (nNewElem_Bound != NULL) delete [] nNewElem_Bound; - if (Marker_All_SendRecv != NULL) delete [] Marker_All_SendRecv; - if (Tag_to_Marker != NULL) delete [] Tag_to_Marker; - - if (beg_node != NULL) delete [] beg_node; - if (end_node != NULL) delete [] end_node; - if (nPointLinear != NULL) delete [] nPointLinear; - if (nPointCumulative != NULL) delete [] nPointCumulative; - - if(CustomBoundaryHeatFlux != NULL){ - for(iMarker=0; iMarker < nMarker; iMarker++){ - if (CustomBoundaryHeatFlux[iMarker] != NULL) delete [] CustomBoundaryHeatFlux[iMarker]; - } - delete [] CustomBoundaryHeatFlux; - } - - if(CustomBoundaryTemperature != NULL){ - for(iMarker=0; iMarker < nMarker; iMarker++){ - if(CustomBoundaryTemperature[iMarker] != NULL) delete [] CustomBoundaryTemperature[iMarker]; - } - delete [] CustomBoundaryTemperature; - } - - /*--- Delete structures for MPI point-to-point communication. ---*/ - - if (bufD_P2PRecv != NULL) delete [] bufD_P2PRecv; - if (bufD_P2PSend != NULL) delete [] bufD_P2PSend; - - if (bufS_P2PRecv != NULL) delete [] bufS_P2PRecv; - if (bufS_P2PSend != NULL) delete [] bufS_P2PSend; - - if (req_P2PSend != NULL) delete [] req_P2PSend; - if (req_P2PRecv != NULL) delete [] req_P2PRecv; - - if (nPoint_P2PRecv != NULL) delete [] nPoint_P2PRecv; - if (nPoint_P2PSend != NULL) delete [] nPoint_P2PSend; - - if (Neighbors_P2PSend != NULL) delete [] Neighbors_P2PSend; - if (Neighbors_P2PRecv != NULL) delete [] Neighbors_P2PRecv; - - if (Local_Point_P2PSend != NULL) delete [] Local_Point_P2PSend; - if (Local_Point_P2PRecv != NULL) delete [] Local_Point_P2PRecv; - - /*--- Delete structures for MPI periodic communication. ---*/ - - if (bufD_PeriodicRecv != NULL) delete [] bufD_PeriodicRecv; - if (bufD_PeriodicSend != NULL) delete [] bufD_PeriodicSend; - - if (bufS_PeriodicRecv != NULL) delete [] bufS_PeriodicRecv; - if (bufS_PeriodicSend != NULL) delete [] bufS_PeriodicSend; - - if (req_PeriodicSend != NULL) delete [] req_PeriodicSend; - if (req_PeriodicRecv != NULL) delete [] req_PeriodicRecv; - - if (nPoint_PeriodicRecv != NULL) delete [] nPoint_PeriodicRecv; - if (nPoint_PeriodicSend != NULL) delete [] nPoint_PeriodicSend; - - if (Neighbors_PeriodicSend != NULL) delete [] Neighbors_PeriodicSend; - if (Neighbors_PeriodicRecv != NULL) delete [] Neighbors_PeriodicRecv; - - if (Local_Point_PeriodicSend != NULL) delete [] Local_Point_PeriodicSend; - if (Local_Point_PeriodicRecv != NULL) delete [] Local_Point_PeriodicRecv; - - if (Local_Marker_PeriodicSend != NULL) delete [] Local_Marker_PeriodicSend; - if (Local_Marker_PeriodicRecv != NULL) delete [] Local_Marker_PeriodicRecv; - -} - -void CGeometry::PreprocessP2PComms(CGeometry *geometry, - CConfig *config) { - - /*--- We start with the send and receive lists already available in - the form of SEND_RECEIVE boundary markers. We will loop through - these markers and establish the neighboring ranks and number of - send/recv points per pair. We will store this information and set - up persistent data structures so that we can reuse them throughout - the calculation for any point-to-point communications. The goal - is to break the non-blocking comms into InitiateComms() and - CompleteComms() in separate routines so that we can overlap the - communication and computation to hide the communication latency. ---*/ - - /*--- Local variables. ---*/ - - unsigned short iMarker; - unsigned long nVertexS, nVertexR, iVertex, MarkerS, MarkerR; - - int iRank, iSend, iRecv, count; - - /*--- Create some temporary structures for tracking sends/recvs. ---*/ - - int *nPoint_Send_All = new int[size+1]; nPoint_Send_All[0] = 0; - int *nPoint_Recv_All = new int[size+1]; nPoint_Recv_All[0] = 0; - int *nPoint_Flag = new int[size]; - - for (iRank = 0; iRank < size; iRank++) { - nPoint_Send_All[iRank] = 0; nPoint_Recv_All[iRank] = 0; nPoint_Flag[iRank]= -1; - } - nPoint_Send_All[size] = 0; nPoint_Recv_All[size] = 0; - - /*--- Loop through all of our SEND_RECEIVE markers and track - our sends with each rank. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - /*--- Get the destination rank and number of points to send. ---*/ - - iRank = config->GetMarker_All_SendRecv(iMarker)-1; - nVertexS = geometry->nVertex[iMarker]; - - /*--- 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; - nPoint_Send_All[iRank+1] += nVertexS; - } - - } - } - - delete [] nPoint_Flag; - - /*--- Communicate the number of points to be sent/recv'd amongst - all processors. After this communication, each proc knows how - many cells it will receive from each other processor. ---*/ - - SU2_MPI::Alltoall(&(nPoint_Send_All[1]), 1, MPI_INT, - &(nPoint_Recv_All[1]), 1, MPI_INT, MPI_COMM_WORLD); - - /*--- Prepare to send connectivities. First check how many - messages we will be sending and receiving. Here we also put - the counters into cumulative storage format to make the - communications simpler. ---*/ - - nP2PSend = 0; nP2PRecv = 0; - - for (iRank = 0; iRank < size; iRank++) { - if ((iRank != rank) && (nPoint_Send_All[iRank+1] > 0)) nP2PSend++; - if ((iRank != rank) && (nPoint_Recv_All[iRank+1] > 0)) nP2PRecv++; - - nPoint_Send_All[iRank+1] += nPoint_Send_All[iRank]; - nPoint_Recv_All[iRank+1] += nPoint_Recv_All[iRank]; - } - - /*--- Allocate only as much memory as we need for the P2P neighbors. ---*/ - - nPoint_P2PSend = new int[nP2PSend+1]; nPoint_P2PSend[0] = 0; - nPoint_P2PRecv = new int[nP2PRecv+1]; nPoint_P2PRecv[0] = 0; - - Neighbors_P2PSend = new int[nP2PSend]; - Neighbors_P2PRecv = new int[nP2PRecv]; - - iSend = 0; iRecv = 0; - for (iRank = 0; iRank < size; iRank++) { - - if ((nPoint_Send_All[iRank+1] > nPoint_Send_All[iRank]) && (iRank != rank)) { - Neighbors_P2PSend[iSend] = iRank; - nPoint_P2PSend[iSend+1] = nPoint_Send_All[iRank+1]; - iSend++; - } - - if ((nPoint_Recv_All[iRank+1] > nPoint_Recv_All[iRank]) && (iRank != rank)) { - Neighbors_P2PRecv[iRecv] = iRank; - nPoint_P2PRecv[iRecv+1] = nPoint_Recv_All[iRank+1]; - iRecv++; - } - - } - - /*--- Create a reverse mapping of the message to the rank so that we - can quickly access the correct data in the buffers when receiving - messages dynamically. ---*/ - - P2PSend2Neighbor.clear(); - for (iSend = 0; iSend < nP2PSend; iSend++) - P2PSend2Neighbor[Neighbors_P2PSend[iSend]] = iSend; - - P2PRecv2Neighbor.clear(); - for (iRecv = 0; iRecv < nP2PRecv; iRecv++) - P2PRecv2Neighbor[Neighbors_P2PRecv[iRecv]] = iRecv; - - delete [] nPoint_Send_All; - delete [] nPoint_Recv_All; - - /*--- Allocate the memory that we need for receiving the conn - values and then cue up the non-blocking receives. Note that - we do not include our own rank in the communications. We will - directly copy our own data later. ---*/ - - Local_Point_P2PSend = NULL; - Local_Point_P2PSend = new unsigned long[nPoint_P2PSend[nP2PSend]]; - for (iSend = 0; iSend < nPoint_P2PSend[nP2PSend]; iSend++) - Local_Point_P2PSend[iSend] = 0; - - Local_Point_P2PRecv = NULL; - Local_Point_P2PRecv = new unsigned long[nPoint_P2PRecv[nP2PRecv]]; - for (iRecv = 0; iRecv < nPoint_P2PRecv[nP2PRecv]; iRecv++) - Local_Point_P2PRecv[iRecv] = 0; - - /*--- We allocate the memory for communicating values in a later step - once we know the maximum packet size that we need to communicate. This - memory is deallocated and reallocated automatically in the case that - the previously allocated memory is not sufficient. ---*/ - - bufD_P2PSend = NULL; - bufD_P2PRecv = NULL; - - bufS_P2PSend = NULL; - bufS_P2PRecv = NULL; - - /*--- Allocate memory for the MPI requests if we need to communicate. ---*/ - - if (nP2PSend > 0) { - req_P2PSend = new SU2_MPI::Request[nP2PSend]; - } - if (nP2PRecv > 0) { - req_P2PRecv = new SU2_MPI::Request[nP2PRecv]; - } - - /*--- Build lists of local index values for send. ---*/ - - count = 0; - for (iSend = 0; iSend < nP2PSend; iSend++) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; - nVertexS = geometry->nVertex[MarkerS]; - iRank = config->GetMarker_All_SendRecv(MarkerS)-1; - - if (iRank == Neighbors_P2PSend[iSend]) { - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - Local_Point_P2PSend[count] = geometry->vertex[MarkerS][iVertex]->GetNode(); - count++; - } - } - - } - } - } - - /*--- Build lists of local index values for receive. ---*/ - - count = 0; - for (iRecv = 0; iRecv < nP2PRecv; iRecv++) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerR = iMarker+1; - nVertexR = geometry->nVertex[MarkerR]; - iRank = abs(config->GetMarker_All_SendRecv(MarkerR))-1; - - if (iRank == Neighbors_P2PRecv[iRecv]) { - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - Local_Point_P2PRecv[count] = geometry->vertex[MarkerR][iVertex]->GetNode(); - count++; - } - } - - } - } - } - - /*--- In the future, some additional data structures could be created - here to separate the interior and boundary nodes in order to help - further overlap computation and communication. ---*/ - -} - -void CGeometry::AllocateP2PComms(unsigned short val_countPerPoint) { - - /*--- This routine is activated whenever we attempt to perform - a point-to-point MPI communication with our neighbors but the - memory buffer allocated is not large enough for the packet size. - Therefore, we deallocate the previously allocated space and - reallocate a large enough array. Note that after the first set - communications, this routine will not need to be called again. ---*/ - - int iSend, iRecv; - - /*--- Store the larger packet size to the class data. ---*/ - - countPerPoint = val_countPerPoint; - - /*-- Deallocate and reallocate our su2double cummunication memory. ---*/ - - if (bufD_P2PSend != NULL) delete [] bufD_P2PSend; - - bufD_P2PSend = new su2double[countPerPoint*nPoint_P2PSend[nP2PSend]]; - for (iSend = 0; iSend < countPerPoint*nPoint_P2PSend[nP2PSend]; iSend++) - bufD_P2PSend[iSend] = 0.0; - - if (bufD_P2PRecv != NULL) delete [] bufD_P2PRecv; - - bufD_P2PRecv = new su2double[countPerPoint*nPoint_P2PRecv[nP2PRecv]]; - for (iRecv = 0; iRecv < countPerPoint*nPoint_P2PRecv[nP2PRecv]; iRecv++) - bufD_P2PRecv[iRecv] = 0.0; - - if (bufS_P2PSend != NULL) delete [] bufS_P2PSend; - - bufS_P2PSend = new unsigned short[countPerPoint*nPoint_P2PSend[nP2PSend]]; - for (iSend = 0; iSend < countPerPoint*nPoint_P2PSend[nP2PSend]; iSend++) - bufS_P2PSend[iSend] = 0; - - if (bufS_P2PRecv != NULL) delete [] bufS_P2PRecv; - - bufS_P2PRecv = new unsigned short[countPerPoint*nPoint_P2PRecv[nP2PRecv]]; - for (iRecv = 0; iRecv < countPerPoint*nPoint_P2PRecv[nP2PRecv]; iRecv++) - bufS_P2PRecv[iRecv] = 0; - -} - -void CGeometry::PostP2PRecvs(CGeometry *geometry, - CConfig *config, - unsigned short commType, - bool val_reverse) { - - /*--- Local variables ---*/ - - int iMessage, iRecv, offset, nPointP2P, count, source, tag; - - /*--- Launch the non-blocking recv's first. Note that we have stored - the counts and sources, so we can launch these before we even load - the data and send from the neighbor ranks. ---*/ - - iMessage = 0; - for (iRecv = 0; iRecv < nP2PRecv; iRecv++) { - - /*--- In some instances related to the adjoint solver, we need - to reverse the direction of communications such that the normal - send nodes become the recv nodes and vice-versa. ---*/ - - if (val_reverse) { - - /*--- Compute our location in the buffer using the send data - structure since we are reversing the comms. ---*/ - - offset = countPerPoint*nPoint_P2PSend[iRecv]; - - /*--- Take advantage of cumulative storage format to get the number - of elems that we need to recv. Note again that we select the send - points here as the recv points. ---*/ - - nPointP2P = nPoint_P2PSend[iRecv+1] - nPoint_P2PSend[iRecv]; - - /*--- Total count can include multiple pieces of data per element. ---*/ - - count = countPerPoint*nPointP2P; - - /*--- Get the rank from which we receive the message. Note again - that we use the send rank as the source instead of the recv rank. ---*/ - - source = Neighbors_P2PSend[iRecv]; - tag = source + 1; - - /*--- Post non-blocking recv for this proc. Note that we use the - send buffer here too. This is important to make sure the arrays - are the correct size. ---*/ - - switch (commType) { - case COMM_TYPE_DOUBLE: - SU2_MPI::Irecv(&(bufD_P2PSend[offset]), count, MPI_DOUBLE, - source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); - break; - case COMM_TYPE_UNSIGNED_SHORT: - SU2_MPI::Irecv(&(bufS_P2PSend[offset]), count, MPI_UNSIGNED_SHORT, - source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); - break; - default: - SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - - } else { - - /*--- Compute our location in the recv buffer. ---*/ - - offset = countPerPoint*nPoint_P2PRecv[iRecv]; - - /*--- Take advantage of cumulative storage format to get the number - of elems that we need to recv. ---*/ - - nPointP2P = nPoint_P2PRecv[iRecv+1] - nPoint_P2PRecv[iRecv]; - - /*--- Total count can include multiple pieces of data per element. ---*/ - - count = countPerPoint*nPointP2P; - - /*--- Get the rank from which we receive the message. ---*/ - - source = Neighbors_P2PRecv[iRecv]; - tag = source + 1; - - /*--- Post non-blocking recv for this proc. ---*/ - - switch (commType) { - case COMM_TYPE_DOUBLE: - SU2_MPI::Irecv(&(bufD_P2PRecv[offset]), count, MPI_DOUBLE, - source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); - break; - case COMM_TYPE_UNSIGNED_SHORT: - SU2_MPI::Irecv(&(bufS_P2PRecv[offset]), count, MPI_UNSIGNED_SHORT, - source, tag, MPI_COMM_WORLD, &(req_P2PRecv[iMessage])); - break; - default: - SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - - } - - /*--- Increment message counter. ---*/ - - iMessage++; - - } - -} - -void CGeometry::PostP2PSends(CGeometry *geometry, - CConfig *config, - unsigned short commType, - int val_iSend, - bool val_reverse) { - - /*--- Local variables ---*/ - - int iMessage, offset, nPointP2P, count, dest, tag; - - /*--- Post the non-blocking send as soon as the buffer is loaded. ---*/ - - iMessage = val_iSend; - - /*--- In some instances related to the adjoint solver, we need - to reverse the direction of communications such that the normal - send nodes become the recv nodes and vice-versa. ---*/ - - if (val_reverse) { - - /*--- Compute our location in the buffer using the recv data - structure since we are reversing the comms. ---*/ - - offset = countPerPoint*nPoint_P2PRecv[val_iSend]; - - /*--- Take advantage of cumulative storage format to get the number - of points that we need to send. Note again that we select the recv - points here as the send points. ---*/ - - nPointP2P = nPoint_P2PRecv[val_iSend+1] - nPoint_P2PRecv[val_iSend]; - - /*--- Total count can include multiple pieces of data per element. ---*/ - - count = countPerPoint*nPointP2P; - - /*--- Get the rank to which we send the message. Note again - that we use the recv rank as the dest instead of the send rank. ---*/ - - dest = Neighbors_P2PRecv[val_iSend]; - tag = rank + 1; - - /*--- Post non-blocking send for this proc. Note that we use the - send buffer here too. This is important to make sure the arrays - are the correct size. ---*/ - - switch (commType) { - case COMM_TYPE_DOUBLE: - SU2_MPI::Isend(&(bufD_P2PRecv[offset]), count, MPI_DOUBLE, - dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); - break; - case COMM_TYPE_UNSIGNED_SHORT: - SU2_MPI::Isend(&(bufS_P2PRecv[offset]), count, MPI_UNSIGNED_SHORT, - dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); - break; - default: - SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - - } else { - - /*--- Compute our location in the send buffer. ---*/ - - offset = countPerPoint*nPoint_P2PSend[val_iSend]; - - /*--- Take advantage of cumulative storage format to get the number - of points that we need to send. ---*/ - - nPointP2P = nPoint_P2PSend[val_iSend+1] - nPoint_P2PSend[val_iSend]; - - /*--- Total count can include multiple pieces of data per element. ---*/ - - count = countPerPoint*nPointP2P; - - /*--- Get the rank to which we send the message. ---*/ - - dest = Neighbors_P2PSend[val_iSend]; - tag = rank + 1; - - /*--- Post non-blocking send for this proc. ---*/ - - switch (commType) { - case COMM_TYPE_DOUBLE: - SU2_MPI::Isend(&(bufD_P2PSend[offset]), count, MPI_DOUBLE, - dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); - break; - case COMM_TYPE_UNSIGNED_SHORT: - SU2_MPI::Isend(&(bufS_P2PSend[offset]), count, MPI_UNSIGNED_SHORT, - dest, tag, MPI_COMM_WORLD, &(req_P2PSend[iMessage])); - break; - default: - SU2_MPI::Error("Unrecognized data type for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - - } - -} - -void CGeometry::InitiateComms(CGeometry *geometry, - CConfig *config, - unsigned short commType) { - - /*--- Local variables ---*/ - - unsigned short iDim; - unsigned short COUNT_PER_POINT = 0; - unsigned short MPI_TYPE = 0; - - unsigned long iPoint, msg_offset, buf_offset; - - int iMessage, iSend, nSend; - - /*--- Set the size of the data packet and type depending on quantity. ---*/ - - switch (commType) { - case COORDINATES: - COUNT_PER_POINT = nDim; - MPI_TYPE = COMM_TYPE_DOUBLE; - break; - case GRID_VELOCITY: - COUNT_PER_POINT = nDim; - MPI_TYPE = COMM_TYPE_DOUBLE; - break; - case COORDINATES_OLD: - if (config->GetTime_Marching() == DT_STEPPING_2ND) - COUNT_PER_POINT = nDim*2; - else - COUNT_PER_POINT = nDim; - MPI_TYPE = COMM_TYPE_DOUBLE; - break; - case MAX_LENGTH: - COUNT_PER_POINT = 1; - MPI_TYPE = COMM_TYPE_DOUBLE; - break; - case NEIGHBORS: - COUNT_PER_POINT = 1; - MPI_TYPE = COMM_TYPE_UNSIGNED_SHORT; - break; - default: - SU2_MPI::Error("Unrecognized quantity for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - - /*--- Check to make sure we have created a large enough buffer - for these comms during preprocessing. This is only for the su2double - buffer. It will be reallocated whenever we find a larger count - per point. After the first cycle of comms, this should be inactive. ---*/ - - if (COUNT_PER_POINT > geometry->countPerPoint) { - geometry->AllocateP2PComms(COUNT_PER_POINT); - } - - /*--- Set some local pointers to make access simpler. ---*/ - - su2double *bufDSend = geometry->bufD_P2PSend; - unsigned short *bufSSend = geometry->bufS_P2PSend; - - su2double *vector = NULL; - - /*--- Load the specified quantity from the solver into the generic - communication buffer in the geometry class. ---*/ - - if (nP2PSend > 0) { - - /*--- Post all non-blocking recvs first before sends. ---*/ - - geometry->PostP2PRecvs(geometry, config, MPI_TYPE, false); - - for (iMessage = 0; iMessage < nP2PSend; iMessage++) { - - /*--- Get the offset in the buffer for the start of this message. ---*/ - - msg_offset = nPoint_P2PSend[iMessage]; - - /*--- Total count can include multiple pieces of data per element. ---*/ - - nSend = (nPoint_P2PSend[iMessage+1] - nPoint_P2PSend[iMessage]); - - for (iSend = 0; iSend < nSend; iSend++) { - - /*--- Get the local index for this communicated data. ---*/ - - iPoint = geometry->Local_Point_P2PSend[msg_offset + iSend]; - - /*--- Compute the offset in the recv buffer for this point. ---*/ - - buf_offset = (msg_offset + iSend)*countPerPoint; - - switch (commType) { - case COORDINATES: - vector = node[iPoint]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) - bufDSend[buf_offset+iDim] = vector[iDim]; - break; - case GRID_VELOCITY: - vector = node[iPoint]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - bufDSend[buf_offset+iDim] = vector[iDim]; - break; - case COORDINATES_OLD: - vector = node[iPoint]->GetCoord_n(); - for (iDim = 0; iDim < nDim; iDim++) { - bufDSend[buf_offset+iDim] = vector[iDim]; - } - if (config->GetTime_Marching() == DT_STEPPING_2ND) { - vector = node[iPoint]->GetCoord_n1(); - for (iDim = 0; iDim < nDim; iDim++) { - bufDSend[buf_offset+nDim+iDim] = vector[iDim]; - } - } - break; - case MAX_LENGTH: - bufDSend[buf_offset] = node[iPoint]->GetMaxLength(); - break; - case NEIGHBORS: - bufSSend[buf_offset] = geometry->node[iPoint]->GetnNeighbor(); - break; - default: - SU2_MPI::Error("Unrecognized quantity for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - } - - /*--- Launch the point-to-point MPI send for this message. ---*/ - - geometry->PostP2PSends(geometry, config, MPI_TYPE, iMessage, false); - - } - } - -} - -void CGeometry::CompleteComms(CGeometry *geometry, - CConfig *config, - unsigned short commType) { - - /*--- Local variables ---*/ - - unsigned short iDim; - unsigned long iPoint, iRecv, nRecv, msg_offset, buf_offset; - - int ind, source, iMessage, jRecv; - SU2_MPI::Status status; - - /*--- Set some local pointers to make access simpler. ---*/ - - su2double *bufDRecv = geometry->bufD_P2PRecv; - unsigned short *bufSRecv = geometry->bufS_P2PRecv; - - /*--- Store the data that was communicated into the appropriate - location within the local class data structures. Note that we - recv and store the data in any order to take advantage of the - non-blocking comms. ---*/ - - if (nP2PRecv > 0) { - - for (iMessage = 0; iMessage < nP2PRecv; iMessage++) { - - /*--- For efficiency, recv the messages dynamically based on - the order they arrive. ---*/ - - SU2_MPI::Waitany(nP2PRecv, req_P2PRecv, &ind, &status); - - /*--- Once we have recv'd a message, get the source rank. ---*/ - - source = status.MPI_SOURCE; - - /*--- We know the offsets based on the source rank. ---*/ - - jRecv = P2PRecv2Neighbor[source]; - - /*--- Get the offset in the buffer for the start of this message. ---*/ - - msg_offset = nPoint_P2PRecv[jRecv]; - - /*--- Get the number of packets to be received in this message. ---*/ - - nRecv = nPoint_P2PRecv[jRecv+1] - nPoint_P2PRecv[jRecv]; - - for (iRecv = 0; iRecv < nRecv; iRecv++) { - - /*--- Get the local index for this communicated data. ---*/ - - iPoint = geometry->Local_Point_P2PRecv[msg_offset + iRecv]; - - /*--- Compute the total offset in the recv buffer for this point. ---*/ - - buf_offset = (msg_offset + iRecv)*countPerPoint; - - /*--- Store the data correctly depending on the quantity. ---*/ - - switch (commType) { - case COORDINATES: - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetCoord(iDim, bufDRecv[buf_offset+iDim]); - break; - case GRID_VELOCITY: - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint]->SetGridVel(iDim, bufDRecv[buf_offset+iDim]); - break; - case COORDINATES_OLD: - node[iPoint]->SetCoord_n(&bufDRecv[buf_offset]); - if (config->GetTime_Marching() == DT_STEPPING_2ND) - node[iPoint]->SetCoord_n1(&bufDRecv[buf_offset+nDim]); - break; - case MAX_LENGTH: - node[iPoint]->SetMaxLength(bufDRecv[buf_offset]); - break; - case NEIGHBORS: - node[iPoint]->SetnNeighbor(bufSRecv[buf_offset]); - break; - default: - SU2_MPI::Error("Unrecognized quantity for point-to-point MPI comms.", - CURRENT_FUNCTION); - break; - } - } - } - - /*--- Verify that all non-blocking point-to-point sends have finished. - Note that this should be satisfied, as we have received all of the - data in the loop above at this point. ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Waitall(nP2PSend, req_P2PSend, MPI_STATUS_IGNORE); -#endif - - } - -} - -void CGeometry::PreprocessPeriodicComms(CGeometry *geometry, - CConfig *config) { - - /*--- We start with the send and receive lists already available in - the form of stored periodic point-donor pairs. We will loop through - these markers and establish the neighboring ranks and number of - send/recv points per pair. We will store this information and set - up persistent data structures so that we can reuse them throughout - the calculation for any periodic boundary communications. The goal - is to break the non-blocking comms into InitiatePeriodicComms() and - CompletePeriodicComms() in separate routines so that we can overlap the - communication and computation to hide the communication latency. ---*/ - - /*--- Local variables. ---*/ - - unsigned short iMarker; - unsigned long iPoint, iVertex, iPeriodic; - - int iRank, iSend, iRecv, ii, jj; - - /*--- Create some temporary structures for tracking sends/recvs. ---*/ - - int *nPoint_Send_All = new int[size+1]; nPoint_Send_All[0] = 0; - int *nPoint_Recv_All = new int[size+1]; nPoint_Recv_All[0] = 0; - int *nPoint_Flag = new int[size]; - - for (iRank = 0; iRank < size; iRank++) { - nPoint_Send_All[iRank] = 0; - nPoint_Recv_All[iRank] = 0; - nPoint_Flag[iRank]= -1; - } - nPoint_Send_All[size] = 0; nPoint_Recv_All[size] = 0; - - /*--- Loop through all of our periodic markers and track - our sends with each rank. ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - iPeriodic = config->GetMarker_All_PerBound(iMarker); - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Get the current periodic point index. We only communicate - the owned nodes on a rank, as the MPI comms will take care of - the halos after completing the periodic comms. ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Get the rank that holds the matching periodic point - on the other marker in the periodic pair. ---*/ - - iRank = (int)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; - nPoint_Send_All[iRank+1] += 1; - } - - } - } - } - } - - delete [] nPoint_Flag; - - /*--- Communicate the number of points to be sent/recv'd amongst - all processors. After this communication, each proc knows how - many periodic points it will receive from each other processor. ---*/ - - SU2_MPI::Alltoall(&(nPoint_Send_All[1]), 1, MPI_INT, - &(nPoint_Recv_All[1]), 1, MPI_INT, MPI_COMM_WORLD); - - /*--- Check how many messages we will be sending and receiving. - Here we also put the counters into cumulative storage format to - make the communications simpler. Note that we are allowing each - rank to communicate to themselves in these counters, although - it will not be done through MPI. ---*/ - - nPeriodicSend = 0; nPeriodicRecv = 0; - - for (iRank = 0; iRank < size; iRank++) { - if ((nPoint_Send_All[iRank+1] > 0)) nPeriodicSend++; - if ((nPoint_Recv_All[iRank+1] > 0)) nPeriodicRecv++; - - nPoint_Send_All[iRank+1] += nPoint_Send_All[iRank]; - nPoint_Recv_All[iRank+1] += nPoint_Recv_All[iRank]; - } - - /*--- Allocate only as much memory as needed for the periodic neighbors. ---*/ - - nPoint_PeriodicSend = new int[nPeriodicSend+1]; nPoint_PeriodicSend[0] = 0; - nPoint_PeriodicRecv = new int[nPeriodicRecv+1]; nPoint_PeriodicRecv[0] = 0; - - Neighbors_PeriodicSend = new int[nPeriodicSend]; - Neighbors_PeriodicRecv = new int[nPeriodicRecv]; - - iSend = 0; iRecv = 0; - for (iRank = 0; iRank < size; iRank++) { - if ((nPoint_Send_All[iRank+1] > nPoint_Send_All[iRank])) { - Neighbors_PeriodicSend[iSend] = iRank; - nPoint_PeriodicSend[iSend+1] = nPoint_Send_All[iRank+1]; - iSend++; - } - if ((nPoint_Recv_All[iRank+1] > nPoint_Recv_All[iRank])) { - Neighbors_PeriodicRecv[iRecv] = iRank; - nPoint_PeriodicRecv[iRecv+1] = nPoint_Recv_All[iRank+1]; - iRecv++; - } - } - - /*--- Create a reverse mapping of the message to the rank so that we - can quickly access the correct data in the buffers when receiving - messages dynamically later during the iterations. ---*/ - - PeriodicSend2Neighbor.clear(); - for (iSend = 0; iSend < nPeriodicSend; iSend++) - PeriodicSend2Neighbor[Neighbors_PeriodicSend[iSend]] = iSend; - - PeriodicRecv2Neighbor.clear(); - for (iRecv = 0; iRecv < nPeriodicRecv; iRecv++) - PeriodicRecv2Neighbor[Neighbors_PeriodicRecv[iRecv]] = iRecv; - - delete [] nPoint_Send_All; - delete [] nPoint_Recv_All; - - /*--- Allocate the memory to store the local index values for both - the send and receive periodic points and periodic index. ---*/ - - Local_Point_PeriodicSend = NULL; - Local_Point_PeriodicSend = new unsigned long[nPoint_PeriodicSend[nPeriodicSend]]; - for (iSend = 0; iSend < nPoint_PeriodicSend[nPeriodicSend]; iSend++) - Local_Point_PeriodicSend[iSend] = 0; - - Local_Marker_PeriodicSend = NULL; - Local_Marker_PeriodicSend = new unsigned long[nPoint_PeriodicSend[nPeriodicSend]]; - for (iSend = 0; iSend < nPoint_PeriodicSend[nPeriodicSend]; iSend++) - Local_Marker_PeriodicSend[iSend] = 0; - - Local_Point_PeriodicRecv = NULL; - Local_Point_PeriodicRecv = new unsigned long[nPoint_PeriodicRecv[nPeriodicRecv]]; - for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]; iRecv++) - Local_Point_PeriodicRecv[iRecv] = 0; - - Local_Marker_PeriodicRecv = NULL; - Local_Marker_PeriodicRecv = new unsigned long[nPoint_PeriodicRecv[nPeriodicRecv]]; - for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]; iRecv++) - Local_Marker_PeriodicRecv[iRecv] = 0; - - /*--- We allocate the buffers for communicating values in a later step - once we know the maximum packet size that we need to communicate. This - memory is deallocated and reallocated automatically in the case that - the previously allocated memory is not sufficient. ---*/ - - bufD_PeriodicSend = NULL; - bufD_PeriodicRecv = NULL; - - bufS_PeriodicSend = NULL; - bufS_PeriodicRecv = NULL; - - /*--- Allocate memory for the MPI requests if we need to communicate. ---*/ - - if (nPeriodicSend > 0) { - req_PeriodicSend = new SU2_MPI::Request[nPeriodicSend]; - } - if (nPeriodicRecv > 0) { - req_PeriodicRecv = new SU2_MPI::Request[nPeriodicRecv]; - } - - /*--- Allocate arrays for sending the periodic point index and marker - index to the recv rank so that it can store the local values. Therefore, - the recv rank can quickly loop through the buffers to unpack the data. ---*/ - - unsigned short nPackets = 2; - unsigned long *idSend = new unsigned long[nPoint_PeriodicSend[nPeriodicSend]*nPackets]; - for (iSend = 0; iSend < nPoint_PeriodicSend[nPeriodicSend]*nPackets; iSend++) - idSend[iSend] = 0; - - /*--- Build the lists of local index and periodic marker index values. ---*/ - - ii = 0; jj = 0; - for (iSend = 0; iSend < nPeriodicSend; iSend++) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - iPeriodic = config->GetMarker_All_PerBound(iMarker); - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - - /*--- Get the current periodic point index. We only communicate - the owned nodes on a rank, as the MPI comms will take care of - the halos after completing the periodic comms. ---*/ - - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - - if (geometry->node[iPoint]->GetDomain()) { - - /*--- Get the rank that holds the matching periodic point - on the other marker in the periodic pair. ---*/ - - iRank = (int)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 - index on the matching periodic point and the periodic marker - index to be communicated to the recv rank. ---*/ - - if (iRank == Neighbors_PeriodicSend[iSend]) { - Local_Point_PeriodicSend[ii] = iPoint; - Local_Marker_PeriodicSend[ii] = (unsigned long)iMarker; - jj = ii*nPackets; - idSend[jj] = geometry->vertex[iMarker][iVertex]->GetDonorPoint(); - jj++; - idSend[jj] = (unsigned long)iPeriodic; - ii++; - } - - } - } - } - } - } - - /*--- Allocate arrays for receiving the periodic point index and marker - index to the recv rank so that it can store the local values. ---*/ - - unsigned long *idRecv = new unsigned long[nPoint_PeriodicRecv[nPeriodicRecv]*nPackets]; - for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]*nPackets; iRecv++) - idRecv[iRecv] = 0; - -#ifdef HAVE_MPI - - int iMessage, offset, count, source, dest, tag; - - /*--- Launch the non-blocking recv's first. Note that we have stored - the counts and sources, so we can launch these before we even load - the data and send from the periodically matching ranks. ---*/ - - iMessage = 0; - for (iRecv = 0; iRecv < nPeriodicRecv; iRecv++) { - - /*--- Compute our location in the recv buffer. ---*/ - - offset = nPackets*nPoint_PeriodicRecv[iRecv]; - - /*--- Take advantage of cumulative storage format to get the number - of elems that we need to recv. ---*/ - - count = nPackets*(nPoint_PeriodicRecv[iRecv+1] - nPoint_PeriodicRecv[iRecv]); - - /*--- Get the rank from which we receive the message. ---*/ - - source = Neighbors_PeriodicRecv[iRecv]; - tag = source + 1; - - /*--- Post non-blocking recv for this proc. ---*/ - - SU2_MPI::Irecv(&(static_cast(idRecv)[offset]), - count, MPI_UNSIGNED_LONG, source, tag, MPI_COMM_WORLD, - &(req_PeriodicRecv[iMessage])); - - /*--- Increment message counter. ---*/ - - iMessage++; - - } - - /*--- Post the non-blocking sends. ---*/ - - iMessage = 0; - for (iSend = 0; iSend < nPeriodicSend; iSend++) { - - /*--- Compute our location in the send buffer. ---*/ - - offset = nPackets*nPoint_PeriodicSend[iSend]; - - /*--- Take advantage of cumulative storage format to get the number - of points that we need to send. ---*/ - - count = nPackets*(nPoint_PeriodicSend[iSend+1] - nPoint_PeriodicSend[iSend]); - - /*--- Get the rank to which we send the message. ---*/ - - dest = Neighbors_PeriodicSend[iSend]; - tag = rank + 1; - - /*--- Post non-blocking send for this proc. ---*/ - - SU2_MPI::Isend(&(static_cast(idSend)[offset]), - count, MPI_UNSIGNED_LONG, dest, tag, MPI_COMM_WORLD, - &(req_PeriodicSend[iMessage])); - - /*--- Increment message counter. ---*/ - - iMessage++; - - } - - /*--- Wait for the non-blocking comms to complete. ---*/ - - SU2_MPI::Waitall(nPeriodicSend, req_PeriodicSend, MPI_STATUS_IGNORE); - SU2_MPI::Waitall(nPeriodicRecv, req_PeriodicRecv, MPI_STATUS_IGNORE); - -#else - - /*--- Copy my own rank's data into the recv buffer directly in serial. ---*/ - - int myStart, myFinal; - for (int val_iSend = 0; val_iSend < nPeriodicSend; val_iSend++) { - iRank = geometry->PeriodicRecv2Neighbor[rank]; - iRecv = geometry->nPoint_PeriodicRecv[iRank]*nPackets; - myStart = nPoint_PeriodicSend[val_iSend]*nPackets; - myFinal = nPoint_PeriodicSend[val_iSend+1]*nPackets; - for (iSend = myStart; iSend < myFinal; iSend++) { - idRecv[iRecv] = idSend[iSend]; - iRecv++; - } - } - -#endif - - /*--- Store the local periodic point and marker index values in our - data structures so we can quickly unpack data during the iterations. ---*/ - - ii = 0; - for (iRecv = 0; iRecv < nPoint_PeriodicRecv[nPeriodicRecv]; iRecv++) { - Local_Point_PeriodicRecv[iRecv] = idRecv[ii]; ii++; - Local_Marker_PeriodicRecv[iRecv] = idRecv[ii]; ii++; - } - - delete [] idSend; - delete [] idRecv; - -} - -void CGeometry::AllocatePeriodicComms(unsigned short val_countPerPeriodicPoint) { - - /*--- This routine is activated whenever we attempt to perform - a periodic MPI communication with our neighbors but the - memory buffer allocated is not large enough for the packet size. - Therefore, we deallocate the previously allocated arrays and - reallocate a large enough array. Note that after the first set - communications, this routine will not need to be called again. ---*/ - - int iSend, iRecv, nSend, nRecv; - - /*--- Store the larger packet size to the class data. ---*/ - - countPerPeriodicPoint = val_countPerPeriodicPoint; - - /*--- Store the total size of the send/recv arrays for clarity. ---*/ - - nSend = countPerPeriodicPoint*nPoint_PeriodicSend[nPeriodicSend]; - nRecv = countPerPeriodicPoint*nPoint_PeriodicRecv[nPeriodicRecv]; - - /*-- Deallocate and reallocate our cummunication memory. ---*/ - - if (bufD_PeriodicSend != NULL) delete [] bufD_PeriodicSend; - - bufD_PeriodicSend = new su2double[nSend]; - for (iSend = 0; iSend < nSend; iSend++) - bufD_PeriodicSend[iSend] = 0.0; - - if (bufD_PeriodicRecv != NULL) delete [] bufD_PeriodicRecv; - - bufD_PeriodicRecv = new su2double[nRecv]; - for (iRecv = 0; iRecv < nRecv; iRecv++) - bufD_PeriodicRecv[iRecv] = 0.0; - - if (bufS_PeriodicSend != NULL) delete [] bufS_PeriodicSend; - - bufS_PeriodicSend = new unsigned short[nSend]; - for (iSend = 0; iSend < nSend; iSend++) - bufS_PeriodicSend[iSend] = 0; - - if (bufS_PeriodicRecv != NULL) delete [] bufS_PeriodicRecv; - - bufS_PeriodicRecv = new unsigned short[nRecv]; - for (iRecv = 0; iRecv < nRecv; iRecv++) - bufS_PeriodicRecv[iRecv] = 0; - -} - -void CGeometry::PostPeriodicRecvs(CGeometry *geometry, - CConfig *config, - unsigned short commType) { - - /*--- In parallel, communicate the data with non-blocking send/recv. ---*/ - -#ifdef HAVE_MPI - - /*--- Local variables ---*/ - - int iMessage, iRecv, offset, nPointPeriodic, count, source, tag; - - /*--- Launch the non-blocking recv's first. Note that we have stored - the counts and sources, so we can launch these before we even load - the data and send from the neighbor ranks. ---*/ - - iMessage = 0; - for (iRecv = 0; iRecv < nPeriodicRecv; iRecv++) { - - /*--- Compute our location in the recv buffer. ---*/ - - offset = countPerPeriodicPoint*nPoint_PeriodicRecv[iRecv]; - - /*--- Take advantage of cumulative storage format to get the number - of elems that we need to recv. ---*/ - - nPointPeriodic = nPoint_PeriodicRecv[iRecv+1] - nPoint_PeriodicRecv[iRecv]; - - /*--- Total count can include multiple pieces of data per element. ---*/ - - count = countPerPeriodicPoint*nPointPeriodic; - - /*--- Get the rank from which we receive the message. ---*/ - - source = Neighbors_PeriodicRecv[iRecv]; - tag = source + 1; - - /*--- Post non-blocking recv for this proc. ---*/ - - switch (commType) { - case COMM_TYPE_DOUBLE: - SU2_MPI::Irecv(&(static_cast(bufD_PeriodicRecv)[offset]), - count, MPI_DOUBLE, source, tag, MPI_COMM_WORLD, - &(req_PeriodicRecv[iMessage])); - break; - case COMM_TYPE_UNSIGNED_SHORT: - SU2_MPI::Irecv(&(static_cast(bufS_PeriodicRecv)[offset]), - count, MPI_UNSIGNED_SHORT, source, tag, MPI_COMM_WORLD, - &(req_PeriodicRecv[iMessage])); - break; - default: - SU2_MPI::Error("Unrecognized data type for periodic MPI comms.", - CURRENT_FUNCTION); - break; - } - - /*--- Increment message counter. ---*/ - - iMessage++; - - } - -#endif - -} - -void CGeometry::PostPeriodicSends(CGeometry *geometry, - CConfig *config, - unsigned short commType, - int val_iSend) { - - /*--- In parallel, communicate the data with non-blocking send/recv. ---*/ - -#ifdef HAVE_MPI - - /*--- Local variables ---*/ - - int iMessage, offset, nPointPeriodic, count, dest, tag; - - /*--- Post the non-blocking send as soon as the buffer is loaded. ---*/ - - iMessage = val_iSend; - - /*--- Compute our location in the send buffer. ---*/ - - offset = countPerPeriodicPoint*nPoint_PeriodicSend[val_iSend]; - - /*--- Take advantage of cumulative storage format to get the number - of points that we need to send. ---*/ - - nPointPeriodic = (nPoint_PeriodicSend[val_iSend+1] - - nPoint_PeriodicSend[val_iSend]); - - /*--- Total count can include multiple pieces of data per element. ---*/ - - count = countPerPeriodicPoint*nPointPeriodic; - - /*--- Get the rank to which we send the message. ---*/ - - dest = Neighbors_PeriodicSend[val_iSend]; - tag = rank + 1; - - /*--- Post non-blocking send for this proc. ---*/ - - switch (commType) { - case COMM_TYPE_DOUBLE: - SU2_MPI::Isend(&(static_cast(bufD_PeriodicSend)[offset]), - count, MPI_DOUBLE, dest, tag, MPI_COMM_WORLD, - &(req_PeriodicSend[iMessage])); - break; - case COMM_TYPE_UNSIGNED_SHORT: - SU2_MPI::Isend(&(static_cast(bufS_PeriodicSend)[offset]), - count, MPI_UNSIGNED_SHORT, dest, tag, MPI_COMM_WORLD, - &(req_PeriodicSend[iMessage])); - break; - default: - SU2_MPI::Error("Unrecognized data type for periodic MPI comms.", - CURRENT_FUNCTION); - break; - } - -#else - - /*--- Copy my own rank's data into the recv buffer directly in serial. ---*/ - - int iSend, myStart, myFinal, iRecv, iRank; - iRank = geometry->PeriodicRecv2Neighbor[rank]; - iRecv = geometry->nPoint_PeriodicRecv[iRank]*countPerPeriodicPoint; - myStart = nPoint_PeriodicSend[val_iSend]*countPerPeriodicPoint; - myFinal = nPoint_PeriodicSend[val_iSend+1]*countPerPeriodicPoint; - for (iSend = myStart; iSend < myFinal; iSend++) { - switch (commType) { - case COMM_TYPE_DOUBLE: - bufD_PeriodicRecv[iRecv] = bufD_PeriodicSend[iSend]; - break; - case COMM_TYPE_UNSIGNED_SHORT: - bufS_PeriodicRecv[iRecv] = bufS_PeriodicSend[iSend]; - break; - default: - SU2_MPI::Error("Unrecognized data type for periodic MPI comms.", - CURRENT_FUNCTION); - break; - } - iRecv++; - } - -#endif - -} - -su2double CGeometry::Point2Plane_Distance(su2double *Coord, su2double *iCoord, su2double *jCoord, su2double *kCoord) { - su2double CrossProduct[3], iVector[3], jVector[3], distance, modulus; - unsigned short iDim; - - for (iDim = 0; iDim < 3; iDim ++) { - iVector[iDim] = jCoord[iDim] - iCoord[iDim]; - jVector[iDim] = kCoord[iDim] - iCoord[iDim]; - } - - CrossProduct[0] = iVector[1]*jVector[2] - iVector[2]*jVector[1]; - CrossProduct[1] = iVector[2]*jVector[0] - iVector[0]*jVector[2]; - CrossProduct[2] = iVector[0]*jVector[1] - iVector[1]*jVector[0]; - - modulus = sqrt(CrossProduct[0]*CrossProduct[0]+CrossProduct[1]*CrossProduct[1]+CrossProduct[2]*CrossProduct[2]); - - distance = 0.0; - for (iDim = 0; iDim < 3; iDim ++) - distance += CrossProduct[iDim]*(Coord[iDim]-iCoord[iDim]); - distance /= modulus; - - return distance; - -} - -long CGeometry::FindEdge(unsigned long first_point, unsigned long second_point) { - unsigned long iPoint = 0; - unsigned short iNode; - for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { - iPoint = node[first_point]->GetPoint(iNode); - if (iPoint == second_point) break; - } - - if (iPoint == second_point) return node[first_point]->GetEdge(iNode); - else { - char buf[100]; - SPRINTF(buf, "Can't find the edge that connects %lu and %lu.", first_point, second_point); - SU2_MPI::Error(buf, CURRENT_FUNCTION); - return 0; - } -} - -bool CGeometry::CheckEdge(unsigned long first_point, unsigned long second_point) { - unsigned long iPoint = 0; - unsigned short iNode; - for (iNode = 0; iNode < node[first_point]->GetnPoint(); iNode++) { - iPoint = node[first_point]->GetPoint(iNode); - if (iPoint == second_point) break; - } - - if (iPoint == second_point) return true; - else return false; - -} - -void CGeometry::SetEdges(void) { - unsigned long iPoint, jPoint; - long iEdge; - unsigned short jNode, iNode; - long TestEdge = 0; - - nEdge = 0; - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - jPoint = node[iPoint]->GetPoint(iNode); - for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) - if (node[jPoint]->GetPoint(jNode) == iPoint) { - TestEdge = node[jPoint]->GetEdge(jNode); - break; - } - if (TestEdge == -1) { - node[iPoint]->SetEdge(nEdge, iNode); - node[jPoint]->SetEdge(nEdge, jNode); - nEdge++; - } - } - - edge = new CEdge*[nEdge]; - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - jPoint = node[iPoint]->GetPoint(iNode); - iEdge = FindEdge(iPoint, jPoint); - if (iPoint < jPoint) edge[iEdge] = new CEdge(iPoint, jPoint, nDim); - } -} - -void CGeometry::SetFaces(void) { - // unsigned long iPoint, jPoint, iFace; - // unsigned short jNode, iNode; - // long TestFace = 0; - // - // nFace = 0; - // for (iPoint = 0; iPoint < nPoint; iPoint++) - // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - // jPoint = node[iPoint]->GetPoint(iNode); - // for (jNode = 0; jNode < node[jPoint]->GetnPoint(); jNode++) - // if (node[jPoint]->GetPoint(jNode) == iPoint) { - // TestFace = node[jPoint]->GetFace(jNode); - // break; - // } - // if (TestFace == -1) { - // node[iPoint]->SetFace(nFace, iNode); - // node[jPoint]->SetFace(nFace, jNode); - // nFace++; - // } - // } - // - // face = new CFace*[nFace]; - // - // for (iPoint = 0; iPoint < nPoint; iPoint++) - // for (iNode = 0; iNode < node[iPoint]->GetnPoint(); iNode++) { - // jPoint = node[iPoint]->GetPoint(iNode); - // iFace = FindFace(iPoint, jPoint); - // if (iPoint < jPoint) face[iFace] = new CFace(iPoint, jPoint, nDim); - // } -} - -void CGeometry::TestGeometry(void) { - - ofstream para_file; - - para_file.open("test_geometry.dat", ios::out); - - su2double *Normal = new su2double[nDim]; - - for (unsigned long iEdge = 0; iEdge < nEdge; iEdge++) { - para_file << "Edge index: " << iEdge << endl; - para_file << " Point index: " << edge[iEdge]->GetNode(0) << "\t" << edge[iEdge]->GetNode(1) << endl; - edge[iEdge]->GetNormal(Normal); - para_file << " Face normal : "; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - para_file << Normal[iDim] << "\t"; - para_file << endl; - } - - para_file << endl; - para_file << endl; - para_file << endl; - para_file << endl; - - for (unsigned short iMarker =0; iMarker < nMarker; iMarker++) { - para_file << "Marker index: " << iMarker << endl; - for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - para_file << " Vertex index: " << iVertex << endl; - para_file << " Point index: " << vertex[iMarker][iVertex]->GetNode() << endl; - para_file << " Point coordinates : "; - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - para_file << node[vertex[iMarker][iVertex]->GetNode()]->GetCoord(iDim) << "\t";} - para_file << endl; - vertex[iMarker][iVertex]->GetNormal(Normal); - para_file << " Face normal : "; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - para_file << Normal[iDim] << "\t"; - para_file << endl; - } - } - - delete [] Normal; - -} - -void CGeometry::SetSpline(vector &x, vector &y, unsigned long n, su2double yp1, su2double ypn, vector &y2) { - unsigned long i, k; - su2double p, qn, sig, un, *u; - - u = new su2double [n]; - - if (yp1 > 0.99e30) // The lower boundary condition is set either to be "nat - y2[0]=u[0]=0.0; // -ural" - else { // or else to have a specified first derivative. - y2[0] = -0.5; - u[0]=(3.0/(x[1]-x[0]))*((y[1]-y[0])/(x[1]-x[0])-yp1); - } - - for (i=2; i<=n-1; i++) { // This is the decomposition loop of the tridiagonal al- - sig=(x[i-1]-x[i-2])/(x[i]-x[i-2]); // gorithm. y2 and u are used for tem- - p=sig*y2[i-2]+2.0; // porary storage of the decomposed - y2[i-1]=(sig-1.0)/p; // factors. - - su2double a1 = (y[i]-y[i-1])/(x[i]-x[i-1]); if (x[i] == x[i-1]) a1 = 1.0; - su2double a2 = (y[i-1]-y[i-2])/(x[i-1]-x[i-2]); if (x[i-1] == x[i-2]) a2 = 1.0; - u[i-1]= a1 - a2; - u[i-1]=(6.0*u[i-1]/(x[i]-x[i-2])-sig*u[i-2])/p; - - } - - if (ypn > 0.99e30) // The upper boundary condition is set either to be - qn=un=0.0; // "natural" - else { // or else to have a specified first derivative. - qn=0.5; - un=(3.0/(x[n-1]-x[n-2]))*(ypn-(y[n-1]-y[n-2])/(x[n-1]-x[n-2])); - } - y2[n-1]=(un-qn*u[n-2])/(qn*y2[n-2]+1.0); - for (k=n-1; k>=1; k--) // This is the backsubstitution loop of the tridiagonal - y2[k-1]=y2[k-1]*y2[k]+u[k-1]; // algorithm. - - delete[] u; - -} - -su2double CGeometry::GetSpline(vector&xa, vector&ya, vector&y2a, unsigned long n, su2double x) { - unsigned long klo, khi, k; - su2double h, b, a, y; - - if (x < xa[0]) x = xa[0]; // Clip max and min values - if (x > xa[n-1]) x = xa[n-1]; - - klo = 1; // We will find the right place in the table by means of - khi = n; // bisection. This is optimal if sequential calls to this - while (khi-klo > 1) { // routine are at random values of x. If sequential calls - k = (khi+klo) >> 1; // are in order, and closely spaced, one would do better - if (xa[k-1] > x) khi = k; // to store previous values of klo and khi and test if - else klo=k; // they remain appropriate on the next call. - } // klo and khi now bracket the input value of x - h = xa[khi-1] - xa[klo-1]; - if (h == 0.0) h = EPS; // cout << "Bad xa input to routine splint" << endl; // The xa?s must be distinct. - a = (xa[khi-1]-x)/h; - b = (x-xa[klo-1])/h; // Cubic spline polynomial is now evaluated. - y = a*ya[klo-1]+b*ya[khi-1]+((a*a*a-a)*y2a[klo-1]+(b*b*b-b)*y2a[khi-1])*(h*h)/6.0; - - return y; -} - -bool CGeometry::SegmentIntersectsPlane(su2double *Segment_P0, su2double *Segment_P1, su2double Variable_P0, su2double Variable_P1, - su2double *Plane_P0, su2double *Plane_Normal, su2double *Intersection, su2double &Variable_Interp) { - su2double u[3], v[3], Denominator, Numerator, Aux, ModU; - su2double epsilon = 1E-6; // An epsilon is added to eliminate, as much as possible, the posibility of a line that intersects a point - unsigned short iDim; - - for (iDim = 0; iDim < 3; iDim++) { - u[iDim] = Segment_P1[iDim] - Segment_P0[iDim]; - v[iDim] = (Plane_P0[iDim]+epsilon) - Segment_P0[iDim]; - } - - ModU = sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2]); - - Numerator = (Plane_Normal[0]+epsilon)*v[0] + (Plane_Normal[1]+epsilon)*v[1] + (Plane_Normal[2]+epsilon)*v[2]; - Denominator = (Plane_Normal[0]+epsilon)*u[0] + (Plane_Normal[1]+epsilon)*u[1] + (Plane_Normal[2]+epsilon)*u[2]; - - if (fabs(Denominator) <= 0.0) return (false); // No intersection. - - Aux = Numerator / Denominator; - - if (Aux < 0.0 || Aux > 1.0) return (false); // No intersection. - - for (iDim = 0; iDim < 3; iDim++) - Intersection[iDim] = Segment_P0[iDim] + Aux * u[iDim]; - - - /*--- Check that the intersection is in the segment ---*/ - - for (iDim = 0; iDim < 3; iDim++) { - u[iDim] = Segment_P0[iDim] - Intersection[iDim]; - v[iDim] = Segment_P1[iDim] - Intersection[iDim]; - } - - Variable_Interp = Variable_P0 + (Variable_P1 - Variable_P0)*sqrt(u[0]*u[0]+u[1]*u[1]+u[2]*u[2])/ModU; - - Denominator = (Plane_Normal[0]+epsilon)*u[0] + (Plane_Normal[1]+epsilon)*u[1] + (Plane_Normal[2]+epsilon)*u[2]; - Numerator = (Plane_Normal[0]+epsilon)*v[0] + (Plane_Normal[1]+epsilon)*v[1] + (Plane_Normal[2]+epsilon)*v[2]; - - Aux = Numerator * Denominator; - - if (Aux > 0.0) return (false); // Intersection outside the segment. - - return (true); - -} - -bool CGeometry::RayIntersectsTriangle(su2double orig[3], su2double dir[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3], - su2double *intersect) { - - su2double edge1[3], edge2[3], tvec[3], pvec[3], qvec[3]; - su2double det, inv_det, t, u, v; - - /*--- Find vectors for two edges sharing vert0 ---*/ - - SUB(edge1, vert1, vert0); - SUB(edge2, vert2, vert0); - - /*--- Begin calculating determinant - also used to calculate U parameter ---*/ - - CROSS(pvec, dir, edge2); - - /*--- If determinant is near zero, ray lies in plane of triangle ---*/ - - det = DOT(edge1, pvec); - - - if (det > -EPSILON && det < EPSILON) return(false); - - inv_det = 1.0 / det; - - /*--- Calculate distance from vert0 to ray origin ---*/ - - SUB(tvec, orig, vert0); - - /*--- Calculate U parameter and test bounds ---*/ - - u = inv_det * DOT(tvec, pvec); - - if (u < 0.0 || u > 1.0) return(false); - - /*--- prepare to test V parameter ---*/ - - CROSS(qvec, tvec, edge1); - - /*--- Calculate V parameter and test bounds ---*/ - - v = inv_det * DOT(dir, qvec); - - if (v < 0.0 || u + v > 1.0) return(false); - - /*--- Calculate t, ray intersects triangle ---*/ - - t = inv_det * DOT(edge2, qvec); - - /*--- Compute the intersection point in cartesian coordinates ---*/ - - intersect[0] = orig[0] + (t * dir[0]); - intersect[1] = orig[1] + (t * dir[1]); - intersect[2] = orig[2] + (t * dir[2]); - - return (true); - -} - -bool CGeometry::SegmentIntersectsLine(su2double point0[2], su2double point1[2], su2double vert0[2], su2double vert1[2]) { - - su2double det, diff0_A, diff0_B, diff1_A, diff1_B, intersect[2]; - - diff0_A = point0[0] - point1[0]; - diff1_A = point0[1] - point1[1]; - - diff0_B = vert0[0] - vert1[0]; - diff1_B = vert0[1] - vert1[1]; - - det = (diff0_A)*(diff1_B) - (diff1_A)*(diff0_B); - - if (det == 0) return false; - - /*--- Compute point of intersection ---*/ - - intersect[0] = ((point0[0]*point1[1] - point0[1]*point1[0])*diff0_B - -(vert0[0]* vert1[1] - vert0[1]* vert1[0])*diff0_A)/det; - - intersect[1] = ((point0[0]*point1[1] - point0[1]*point1[0])*diff1_B - -(vert0[0]* vert1[1] - vert0[1]* vert1[0])*diff1_A)/det; - - - /*--- Check that the point is between the two surface points ---*/ - - su2double dist0, dist1, length; - - dist0 = (intersect[0] - point0[0])*(intersect[0] - point0[0]) - +(intersect[1] - point0[1])*(intersect[1] - point0[1]); - - dist1 = (intersect[0] - point1[0])*(intersect[0] - point1[0]) - +(intersect[1] - point1[1])*(intersect[1] - point1[1]); - - length = diff0_A*diff0_A - +diff1_A*diff1_A; - - if ( (dist0 > length) || (dist1 > length) ) { - return false; - } - - return true; -} - -bool CGeometry::SegmentIntersectsTriangle(su2double point0[3], su2double point1[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3]) { - - su2double dir[3], intersect[3], u[3], v[3], edge1[3], edge2[3], Plane_Normal[3], Denominator, Numerator, Aux; - - SUB(dir, point1, point0); - - if (RayIntersectsTriangle(point0, dir, vert0, vert1, vert2, intersect)) { - - /*--- Check that the intersection is in the segment ---*/ - - SUB(u, point0, intersect); - SUB(v, point1, intersect); - - SUB(edge1, vert1, vert0); - SUB(edge2, vert2, vert0); - CROSS(Plane_Normal, edge1, edge2); - - Denominator = DOT(Plane_Normal, u); - Numerator = DOT(Plane_Normal, v); - - Aux = Numerator * Denominator; - - /*--- Intersection outside the segment ---*/ - - if (Aux > 0.0) return (false); - - } - else { - - /*--- No intersection with the ray ---*/ - - return (false); - - } - - /*--- Intersection inside the segment ---*/ - - return (true); - -} - -void CGeometry::ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Normal, - su2double MinXCoord, su2double MaxXCoord, - su2double MinYCoord, su2double MaxYCoord, - su2double MinZCoord, su2double MaxZCoord, - su2double *FlowVariable, - vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, - vector &Zcoord_Airfoil, vector &Variable_Airfoil, - bool original_surface, CConfig *config) { - - AD_BEGIN_PASSIVE - - unsigned short iMarker, iNode, jNode, iDim, Index = 0; - bool intersect; - long Next_Edge = 0; - unsigned long iPoint, jPoint, iElem, Trailing_Point, Airfoil_Point, iVertex, iEdge, PointIndex, jEdge; - su2double Segment_P0[3] = {0.0, 0.0, 0.0}, Segment_P1[3] = {0.0, 0.0, 0.0}, Variable_P0 = 0.0, Variable_P1 = 0.0, Intersection[3] = {0.0, 0.0, 0.0}, Trailing_Coord, - *VarCoord = NULL, Variable_Interp, v1[3] = {0.0, 0.0, 0.0}, v3[3] = {0.0, 0.0, 0.0}, CrossProduct = 1.0; - bool Found_Edge; - passivedouble Dist_Value; - vector Xcoord_Index0, Ycoord_Index0, Zcoord_Index0, Variable_Index0, Xcoord_Index1, Ycoord_Index1, Zcoord_Index1, Variable_Index1; - vector IGlobalID_Index0, JGlobalID_Index0, IGlobalID_Index1, JGlobalID_Index1, IGlobalID_Airfoil, JGlobalID_Airfoil; - vector Conection_Index0, Conection_Index1; - vector Duplicate; - vector::iterator it; - su2double **Coord_Variation = NULL; - vector XcoordExtra, YcoordExtra, ZcoordExtra, VariableExtra; - vector IGlobalIDExtra, JGlobalIDExtra; - vector AddExtra; - unsigned long EdgeDonor; - bool FoundEdge; - -#ifdef HAVE_MPI - unsigned long nLocalEdge, MaxLocalEdge, *Buffer_Send_nEdge, *Buffer_Receive_nEdge, nBuffer_Coord, nBuffer_Variable, nBuffer_GlobalID; - int nProcessor, iProcessor; - su2double *Buffer_Send_Coord, *Buffer_Receive_Coord; - su2double *Buffer_Send_Variable, *Buffer_Receive_Variable; - unsigned long *Buffer_Send_GlobalID, *Buffer_Receive_GlobalID; -#endif - - Xcoord_Airfoil.clear(); - Ycoord_Airfoil.clear(); - Zcoord_Airfoil.clear(); - Variable_Airfoil.clear(); - IGlobalID_Airfoil.clear(); - JGlobalID_Airfoil.clear(); - - /*--- Set the right plane in 2D (note the change in Y-Z plane) ---*/ - - if (nDim == 2) { - Plane_P0[0] = 0.0; Plane_P0[1] = 0.0; Plane_P0[2] = 0.0; - Plane_Normal[0] = 0.0; Plane_Normal[1] = 1.0; Plane_Normal[2] = 0.0; - } - - /*--- Grid movement is stored using a vertices information, - we should go from vertex to points ---*/ - - if (original_surface == false) { - - Coord_Variation = new su2double *[nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) - Coord_Variation[iPoint] = new su2double [nDim]; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_GeoEval(iMarker) == YES) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - VarCoord = vertex[iMarker][iVertex]->GetVarCoord(); - iPoint = vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) - Coord_Variation[iPoint][iDim] = VarCoord[iDim]; - } - } - } - - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_GeoEval(iMarker) == YES) { - - for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - - PointIndex=0; - - /*--- To decide if an element is going to be used or not should be done element based, - The first step is to compute and average coordinate for the element ---*/ - - su2double AveXCoord = 0.0; - su2double AveYCoord = 0.0; - su2double AveZCoord = 0.0; - - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - AveXCoord += node[iPoint]->GetCoord(0); - AveYCoord += node[iPoint]->GetCoord(1); - if (nDim == 3) AveZCoord += node[iPoint]->GetCoord(2); - } - - AveXCoord /= su2double(bound[iMarker][iElem]->GetnNodes()); - AveYCoord /= su2double(bound[iMarker][iElem]->GetnNodes()); - AveZCoord /= su2double(bound[iMarker][iElem]->GetnNodes()); - - /*--- To only cut one part of the nacelle based on the cross product - of the normal to the plane and a vector that connect the point - with the center line ---*/ - - CrossProduct = 1.0; - - if (config->GetGeo_Description() == NACELLE) { - - su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180; - su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180; - - /*--- Translate to the origin ---*/ - - su2double XCoord_Trans = AveXCoord - config->GetNacelleLocation(0); - su2double YCoord_Trans = AveYCoord - config->GetNacelleLocation(1); - su2double ZCoord_Trans = AveZCoord - config->GetNacelleLocation(2); - - /*--- Apply tilt angle ---*/ - - su2double XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle); - su2double YCoord_Trans_Tilt = YCoord_Trans; - su2double ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle); - - /*--- Apply toe angle ---*/ - - su2double YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle); - su2double ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt; - - /*--- Undo plane rotation, we have already rotated the nacelle ---*/ - - /*--- Undo tilt angle ---*/ - - su2double XPlane_Normal_Tilt = Plane_Normal[0]*cos(-Tilt_Angle) + Plane_Normal[2]*sin(-Tilt_Angle); - su2double YPlane_Normal_Tilt = Plane_Normal[1]; - su2double ZPlane_Normal_Tilt = Plane_Normal[2]*cos(-Tilt_Angle) - Plane_Normal[0]*sin(-Tilt_Angle); - - /*--- Undo toe angle ---*/ - - su2double YPlane_Normal_Tilt_Toe = XPlane_Normal_Tilt*sin(-Toe_Angle) + YPlane_Normal_Tilt*cos(-Toe_Angle); - su2double ZPlane_Normal_Tilt_Toe = ZPlane_Normal_Tilt; - - - v1[1] = YCoord_Trans_Tilt_Toe - 0.0; - v1[2] = ZCoord_Trans_Tilt_Toe - 0.0; - v3[0] = v1[1]*ZPlane_Normal_Tilt_Toe-v1[2]*YPlane_Normal_Tilt_Toe; - CrossProduct = v3[0] * 1.0; - - } - - for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem]->GetNode(iNode); - - for (jNode = 0; jNode < bound[iMarker][iElem]->GetnNodes(); jNode++) { - jPoint = bound[iMarker][iElem]->GetNode(jNode); - - /*--- CrossProduct concept is delicated because it allows triangles where only one side is divided by a plane. - that is going against the concept that all the triangles are divided twice and causes probelms because - Xcoord_Index0.size() > Xcoord_Index1.size()! ---*/ - - if ((jPoint > iPoint) && (CrossProduct >= 0.0) - && ((AveXCoord > MinXCoord) && (AveXCoord < MaxXCoord)) - && ((AveYCoord > MinYCoord) && (AveYCoord < MaxYCoord)) - && ((AveZCoord > MinZCoord) && (AveZCoord < MaxZCoord))) { - - Segment_P0[0] = 0.0; Segment_P0[1] = 0.0; Segment_P0[2] = 0.0; Variable_P0 = 0.0; - Segment_P1[0] = 0.0; Segment_P1[1] = 0.0; Segment_P1[2] = 0.0; Variable_P1 = 0.0; - - - for (iDim = 0; iDim < nDim; iDim++) { - if (original_surface == true) { - Segment_P0[iDim] = node[iPoint]->GetCoord(iDim); - Segment_P1[iDim] = node[jPoint]->GetCoord(iDim); - } - else { - Segment_P0[iDim] = node[iPoint]->GetCoord(iDim) + Coord_Variation[iPoint][iDim]; - Segment_P1[iDim] = node[jPoint]->GetCoord(iDim) + Coord_Variation[jPoint][iDim]; - } - } - - if (FlowVariable != NULL) { - Variable_P0 = FlowVariable[iPoint]; - Variable_P1 = FlowVariable[jPoint]; - } - - /*--- In 2D add the points directly (note the change between Y and Z coordinate) ---*/ - - if (nDim == 2) { - Xcoord_Index0.push_back(Segment_P0[0]); Xcoord_Index1.push_back(Segment_P1[0]); - Ycoord_Index0.push_back(Segment_P0[2]); Ycoord_Index1.push_back(Segment_P1[2]); - Zcoord_Index0.push_back(Segment_P0[1]); Zcoord_Index1.push_back(Segment_P1[1]); - Variable_Index0.push_back(Variable_P0); Variable_Index1.push_back(Variable_P1); - IGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); IGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex()); - JGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); JGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex()); - PointIndex++; - } - - /*--- In 3D compute the intersection ---*/ - - else if (nDim == 3) { - intersect = SegmentIntersectsPlane(Segment_P0, Segment_P1, Variable_P0, Variable_P1, Plane_P0, Plane_Normal, Intersection, Variable_Interp); - if (intersect == true) { - if (PointIndex == 0) { - Xcoord_Index0.push_back(Intersection[0]); - Ycoord_Index0.push_back(Intersection[1]); - Zcoord_Index0.push_back(Intersection[2]); - Variable_Index0.push_back(Variable_Interp); - IGlobalID_Index0.push_back(node[iPoint]->GetGlobalIndex()); - JGlobalID_Index0.push_back(node[jPoint]->GetGlobalIndex()); - } - if (PointIndex == 1) { - Xcoord_Index1.push_back(Intersection[0]); - Ycoord_Index1.push_back(Intersection[1]); - Zcoord_Index1.push_back(Intersection[2]); - Variable_Index1.push_back(Variable_Interp); - IGlobalID_Index1.push_back(node[iPoint]->GetGlobalIndex()); - JGlobalID_Index1.push_back(node[jPoint]->GetGlobalIndex()); - } - PointIndex++; - } - } - - } - } - } - - } - } - } - - if (original_surface == false) { - for (iPoint = 0; iPoint < nPoint; iPoint++) - delete [] Coord_Variation[iPoint]; - delete [] Coord_Variation; - } - -#ifdef HAVE_MPI - - /*--- Copy the coordinates of all the points in the plane to the master node ---*/ - - nLocalEdge = 0, MaxLocalEdge = 0; - nProcessor = size; - - Buffer_Send_nEdge = new unsigned long [1]; - Buffer_Receive_nEdge = new unsigned long [nProcessor]; - - nLocalEdge = Xcoord_Index0.size(); - - Buffer_Send_nEdge[0] = nLocalEdge; - - SU2_MPI::Allreduce(&nLocalEdge, &MaxLocalEdge, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nEdge, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nEdge, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - Buffer_Send_Coord = new su2double [MaxLocalEdge*6]; - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalEdge*6]; - - Buffer_Send_Variable = new su2double [MaxLocalEdge*2]; - Buffer_Receive_Variable = new su2double [nProcessor*MaxLocalEdge*2]; - - Buffer_Send_GlobalID = new unsigned long [MaxLocalEdge*4]; - Buffer_Receive_GlobalID = new unsigned long [nProcessor*MaxLocalEdge*4]; - - nBuffer_Coord = MaxLocalEdge*6; - nBuffer_Variable = MaxLocalEdge*2; - nBuffer_GlobalID = MaxLocalEdge*4; - - for (iEdge = 0; iEdge < nLocalEdge; iEdge++) { - Buffer_Send_Coord[iEdge*6 + 0] = Xcoord_Index0[iEdge]; - Buffer_Send_Coord[iEdge*6 + 1] = Ycoord_Index0[iEdge]; - Buffer_Send_Coord[iEdge*6 + 2] = Zcoord_Index0[iEdge]; - Buffer_Send_Coord[iEdge*6 + 3] = Xcoord_Index1[iEdge]; - Buffer_Send_Coord[iEdge*6 + 4] = Ycoord_Index1[iEdge]; - Buffer_Send_Coord[iEdge*6 + 5] = Zcoord_Index1[iEdge]; - - Buffer_Send_Variable[iEdge*2 + 0] = Variable_Index0[iEdge]; - Buffer_Send_Variable[iEdge*2 + 1] = Variable_Index1[iEdge]; - - Buffer_Send_GlobalID[iEdge*4 + 0] = IGlobalID_Index0[iEdge]; - Buffer_Send_GlobalID[iEdge*4 + 1] = JGlobalID_Index0[iEdge]; - Buffer_Send_GlobalID[iEdge*4 + 2] = IGlobalID_Index1[iEdge]; - Buffer_Send_GlobalID[iEdge*4 + 3] = JGlobalID_Index1[iEdge]; - } - - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_Variable, nBuffer_Variable, MPI_DOUBLE, Buffer_Receive_Variable, nBuffer_Variable, MPI_DOUBLE, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_GlobalID, nBuffer_GlobalID, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalID, nBuffer_GlobalID, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); - - /*--- Clean the vectors before adding the new vertices only to the master node ---*/ - - Xcoord_Index0.clear(); Xcoord_Index1.clear(); - Ycoord_Index0.clear(); Ycoord_Index1.clear(); - Zcoord_Index0.clear(); Zcoord_Index1.clear(); - Variable_Index0.clear(); Variable_Index1.clear(); - IGlobalID_Index0.clear(); IGlobalID_Index1.clear(); - JGlobalID_Index0.clear(); JGlobalID_Index1.clear(); - - /*--- Copy the boundary to the master node vectors ---*/ - - if (rank == MASTER_NODE) { - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iEdge = 0; iEdge < Buffer_Receive_nEdge[iProcessor]; iEdge++) { - Xcoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 0] ); - Ycoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 1] ); - Zcoord_Index0.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 2] ); - Xcoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 3] ); - Ycoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 4] ); - Zcoord_Index1.push_back( Buffer_Receive_Coord[ iProcessor*MaxLocalEdge*6 + iEdge*6 + 5] ); - - Variable_Index0.push_back( Buffer_Receive_Variable[ iProcessor*MaxLocalEdge*2 + iEdge*2 + 0] ); - Variable_Index1.push_back( Buffer_Receive_Variable[ iProcessor*MaxLocalEdge*2 + iEdge*2 + 1] ); - - IGlobalID_Index0.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 0] ); - JGlobalID_Index0.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 1] ); - IGlobalID_Index1.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 2] ); - JGlobalID_Index1.push_back( Buffer_Receive_GlobalID[ iProcessor*MaxLocalEdge*4 + iEdge*4 + 3] ); - - } - } - } - - delete[] Buffer_Send_Coord; delete[] Buffer_Receive_Coord; - delete[] Buffer_Send_Variable; delete[] Buffer_Receive_Variable; - delete[] Buffer_Send_GlobalID; delete[] Buffer_Receive_GlobalID; - delete[] Buffer_Send_nEdge; delete[] Buffer_Receive_nEdge; - -#endif - - if ((rank == MASTER_NODE) && (Xcoord_Index0.size() != 0)) { - - /*--- Remove singular edges ---*/ - - bool Remove; - - do { Remove = false; - for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { - - if (((IGlobalID_Index0[iEdge] == IGlobalID_Index1[iEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[iEdge])) || - ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[iEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[iEdge]))) { - - Xcoord_Index0.erase (Xcoord_Index0.begin() + iEdge); - Ycoord_Index0.erase (Ycoord_Index0.begin() + iEdge); - Zcoord_Index0.erase (Zcoord_Index0.begin() + iEdge); - Variable_Index0.erase (Variable_Index0.begin() + iEdge); - IGlobalID_Index0.erase (IGlobalID_Index0.begin() + iEdge); - JGlobalID_Index0.erase (JGlobalID_Index0.begin() + iEdge); - - Xcoord_Index1.erase (Xcoord_Index1.begin() + iEdge); - Ycoord_Index1.erase (Ycoord_Index1.begin() + iEdge); - Zcoord_Index1.erase (Zcoord_Index1.begin() + iEdge); - Variable_Index1.erase (Variable_Index1.begin() + iEdge); - IGlobalID_Index1.erase (IGlobalID_Index1.begin() + iEdge); - JGlobalID_Index1.erase (JGlobalID_Index1.begin() + iEdge); - - Remove = true; break; - } - if (Remove) break; - } - } while (Remove == true); - - /*--- Remove repeated edges computing distance, this could happend because the MPI ---*/ - - do { Remove = false; - for (iEdge = 0; iEdge < Xcoord_Index0.size()-1; iEdge++) { - for (jEdge = iEdge+1; jEdge < Xcoord_Index0.size(); jEdge++) { - - /*--- Edges with the same orientation ---*/ - - if ((((IGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge])) || - ((IGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]))) && - (((IGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge])) || - ((IGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge])))) { - - Xcoord_Index0.erase (Xcoord_Index0.begin() + jEdge); - Ycoord_Index0.erase (Ycoord_Index0.begin() + jEdge); - Zcoord_Index0.erase (Zcoord_Index0.begin() + jEdge); - Variable_Index0.erase (Variable_Index0.begin() + jEdge); - IGlobalID_Index0.erase (IGlobalID_Index0.begin() + jEdge); - JGlobalID_Index0.erase (JGlobalID_Index0.begin() + jEdge); - - Xcoord_Index1.erase (Xcoord_Index1.begin() + jEdge); - Ycoord_Index1.erase (Ycoord_Index1.begin() + jEdge); - Zcoord_Index1.erase (Zcoord_Index1.begin() + jEdge); - Variable_Index1.erase (Variable_Index1.begin() + jEdge); - IGlobalID_Index1.erase (IGlobalID_Index1.begin() + jEdge); - JGlobalID_Index1.erase (JGlobalID_Index1.begin() + jEdge); - - Remove = true; break; - - } - - /*--- Edges with oposite orientation ---*/ - - if ((((IGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge])) || - ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]))) && - (((IGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge])) || - ((IGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge])))) { - - Xcoord_Index0.erase (Xcoord_Index0.begin() + jEdge); - Ycoord_Index0.erase (Ycoord_Index0.begin() + jEdge); - Zcoord_Index0.erase (Zcoord_Index0.begin() + jEdge); - Variable_Index0.erase (Variable_Index0.begin() + jEdge); - IGlobalID_Index0.erase (IGlobalID_Index0.begin() + jEdge); - JGlobalID_Index0.erase (JGlobalID_Index0.begin() + jEdge); - - Xcoord_Index1.erase (Xcoord_Index1.begin() + jEdge); - Ycoord_Index1.erase (Ycoord_Index1.begin() + jEdge); - Zcoord_Index1.erase (Zcoord_Index1.begin() + jEdge); - Variable_Index1.erase (Variable_Index1.begin() + jEdge); - IGlobalID_Index1.erase (IGlobalID_Index1.begin() + jEdge); - JGlobalID_Index1.erase (JGlobalID_Index1.begin() + jEdge); - - Remove = true; break; - } - if (Remove) break; - } - if (Remove) break; - } - - } while (Remove == true); - - if (Xcoord_Index0.size() != 1) { - - /*--- Rotate from the Y-Z plane to the X-Z plane to reuse the rest of subroutines ---*/ - - if (config->GetGeo_Description() == FUSELAGE) { - su2double Angle = -0.5*PI_NUMBER; - for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { - su2double XCoord = Xcoord_Index0[iEdge]*cos(Angle) - Ycoord_Index0[iEdge]*sin(Angle); - su2double YCoord = Ycoord_Index0[iEdge]*cos(Angle) + Xcoord_Index0[iEdge]*sin(Angle); - su2double ZCoord = Zcoord_Index0[iEdge]; - Xcoord_Index0[iEdge] = XCoord; Ycoord_Index0[iEdge] = YCoord; Zcoord_Index0[iEdge] = ZCoord; - XCoord = Xcoord_Index1[iEdge]*cos(Angle) - Ycoord_Index1[iEdge]*sin(Angle); - YCoord = Ycoord_Index1[iEdge]*cos(Angle) + Xcoord_Index1[iEdge]*sin(Angle); - ZCoord = Zcoord_Index1[iEdge]; - Xcoord_Index1[iEdge] = XCoord; Ycoord_Index1[iEdge] = YCoord; Zcoord_Index1[iEdge] = ZCoord; - } - } - - /*--- Rotate nacelle secction to a X-Z plane to reuse the rest of subroutines ---*/ - - - if (config->GetGeo_Description() == NACELLE) { - - su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180; - su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180; - su2double Theta_deg = atan2(Plane_Normal[1],-Plane_Normal[2])/PI_NUMBER*180 + 180; - su2double Roll_Angle = 0.5*PI_NUMBER - Theta_deg*PI_NUMBER/180; - - su2double XCoord_Trans, YCoord_Trans, ZCoord_Trans, XCoord_Trans_Tilt, YCoord_Trans_Tilt, ZCoord_Trans_Tilt, - XCoord_Trans_Tilt_Toe, YCoord_Trans_Tilt_Toe, ZCoord_Trans_Tilt_Toe, XCoord, YCoord, ZCoord; - - for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { - - /*--- First point of the edge ---*/ - - /*--- Translate to the origin ---*/ - - XCoord_Trans = Xcoord_Index0[iEdge] - config->GetNacelleLocation(0); - YCoord_Trans = Ycoord_Index0[iEdge] - config->GetNacelleLocation(1); - ZCoord_Trans = Zcoord_Index0[iEdge] - config->GetNacelleLocation(2); - - /*--- Apply tilt angle ---*/ - - XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle); - YCoord_Trans_Tilt = YCoord_Trans; - ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle); - - /*--- Apply toe angle ---*/ - - XCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*cos(Toe_Angle) - YCoord_Trans_Tilt*sin(Toe_Angle); - YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle); - ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt; - - /*--- Rotate to X-Z plane (roll) ---*/ - - XCoord = XCoord_Trans_Tilt_Toe; - YCoord = YCoord_Trans_Tilt_Toe*cos(Roll_Angle) - ZCoord_Trans_Tilt_Toe*sin(Roll_Angle); - ZCoord = YCoord_Trans_Tilt_Toe*sin(Roll_Angle) + ZCoord_Trans_Tilt_Toe*cos(Roll_Angle); - - /*--- Update coordinates ---*/ - - Xcoord_Index0[iEdge] = XCoord; Ycoord_Index0[iEdge] = YCoord; Zcoord_Index0[iEdge] = ZCoord; - - /*--- Second point of the edge ---*/ - - /*--- Translate to the origin ---*/ - - XCoord_Trans = Xcoord_Index1[iEdge] - config->GetNacelleLocation(0); - YCoord_Trans = Ycoord_Index1[iEdge] - config->GetNacelleLocation(1); - ZCoord_Trans = Zcoord_Index1[iEdge] - config->GetNacelleLocation(2); - - /*--- Apply tilt angle ---*/ - - XCoord_Trans_Tilt = XCoord_Trans*cos(Tilt_Angle) + ZCoord_Trans*sin(Tilt_Angle); - YCoord_Trans_Tilt = YCoord_Trans; - ZCoord_Trans_Tilt = ZCoord_Trans*cos(Tilt_Angle) - XCoord_Trans*sin(Tilt_Angle); - - /*--- Apply toe angle ---*/ - - XCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*cos(Toe_Angle) - YCoord_Trans_Tilt*sin(Toe_Angle); - YCoord_Trans_Tilt_Toe = XCoord_Trans_Tilt*sin(Toe_Angle) + YCoord_Trans_Tilt*cos(Toe_Angle); - ZCoord_Trans_Tilt_Toe = ZCoord_Trans_Tilt; - - /*--- Rotate to X-Z plane (roll) ---*/ - - XCoord = XCoord_Trans_Tilt_Toe; - YCoord = YCoord_Trans_Tilt_Toe*cos(Roll_Angle) - ZCoord_Trans_Tilt_Toe*sin(Roll_Angle); - ZCoord = YCoord_Trans_Tilt_Toe*sin(Roll_Angle) + ZCoord_Trans_Tilt_Toe*cos(Roll_Angle); - - /*--- Update coordinates ---*/ - - Xcoord_Index1[iEdge] = XCoord; Ycoord_Index1[iEdge] = YCoord; Zcoord_Index1[iEdge] = ZCoord; - - } - } - - - /*--- Identify the extreme of the curve and close it ---*/ - - Conection_Index0.reserve(Xcoord_Index0.size()+1); - Conection_Index1.reserve(Xcoord_Index0.size()+1); - - for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { - Conection_Index0[iEdge] = 0; - Conection_Index1[iEdge] = 0; - } - - for (iEdge = 0; iEdge < Xcoord_Index0.size()-1; iEdge++) { - for (jEdge = iEdge+1; jEdge < Xcoord_Index0.size(); jEdge++) { - - if (((IGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge])) || - ((IGlobalID_Index0[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index0[jEdge]))) - { Conection_Index0[iEdge]++; Conection_Index0[jEdge]++; } - - if (((IGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge])) || - ((IGlobalID_Index0[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index0[iEdge] == IGlobalID_Index1[jEdge]))) - { Conection_Index0[iEdge]++; Conection_Index1[jEdge]++; } - - if (((IGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge])) || - ((IGlobalID_Index1[iEdge] == JGlobalID_Index0[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index0[jEdge]))) - { Conection_Index1[iEdge]++; Conection_Index0[jEdge]++; } - - if (((IGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge])) || - ((IGlobalID_Index1[iEdge] == JGlobalID_Index1[jEdge]) && (JGlobalID_Index1[iEdge] == IGlobalID_Index1[jEdge]))) - { Conection_Index1[iEdge]++; Conection_Index1[jEdge]++; } - - } - } - - /*--- Connect extremes of the curves ---*/ - - /*--- First: Identify the extremes of the curve in the extra vector ---*/ - - for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { - if (Conection_Index0[iEdge] == 0) { - XcoordExtra.push_back(Xcoord_Index0[iEdge]); - YcoordExtra.push_back(Ycoord_Index0[iEdge]); - ZcoordExtra.push_back(Zcoord_Index0[iEdge]); - VariableExtra.push_back(Variable_Index0[iEdge]); - IGlobalIDExtra.push_back(IGlobalID_Index0[iEdge]); - JGlobalIDExtra.push_back(JGlobalID_Index0[iEdge]); - AddExtra.push_back(true); - } - if (Conection_Index1[iEdge] == 0) { - XcoordExtra.push_back(Xcoord_Index1[iEdge]); - YcoordExtra.push_back(Ycoord_Index1[iEdge]); - ZcoordExtra.push_back(Zcoord_Index1[iEdge]); - VariableExtra.push_back(Variable_Index1[iEdge]); - IGlobalIDExtra.push_back(IGlobalID_Index1[iEdge]); - JGlobalIDExtra.push_back(JGlobalID_Index1[iEdge]); - AddExtra.push_back(true); - } - } - - /*--- Second, if it is an open curve then find the closest point to an extreme to close it ---*/ - - if (XcoordExtra.size() > 1) { - - for (iEdge = 0; iEdge < XcoordExtra.size()-1; iEdge++) { - - su2double MinDist = 1E6; FoundEdge = false; EdgeDonor = 0; - for (jEdge = iEdge+1; jEdge < XcoordExtra.size(); jEdge++) { - Dist_Value = sqrt(pow(SU2_TYPE::GetValue(XcoordExtra[iEdge])-SU2_TYPE::GetValue(XcoordExtra[jEdge]), 2.0)); - if ((Dist_Value < MinDist) && (AddExtra[iEdge]) && (AddExtra[jEdge])) { - EdgeDonor = jEdge; FoundEdge = true; - } - } - - if (FoundEdge) { - - /*--- Add first point of the new edge ---*/ - - Xcoord_Index0.push_back (XcoordExtra[iEdge]); - Ycoord_Index0.push_back (YcoordExtra[iEdge]); - Zcoord_Index0.push_back (ZcoordExtra[iEdge]); - Variable_Index0.push_back (VariableExtra[iEdge]); - IGlobalID_Index0.push_back (IGlobalIDExtra[iEdge]); - JGlobalID_Index0.push_back (JGlobalIDExtra[iEdge]); - AddExtra[iEdge] = false; - - /*--- Add second (closest) point of the new edge ---*/ - - Xcoord_Index1.push_back (XcoordExtra[EdgeDonor]); - Ycoord_Index1.push_back (YcoordExtra[EdgeDonor]); - Zcoord_Index1.push_back (ZcoordExtra[EdgeDonor]); - Variable_Index1.push_back (VariableExtra[EdgeDonor]); - IGlobalID_Index1.push_back (IGlobalIDExtra[EdgeDonor]); - JGlobalID_Index1.push_back (JGlobalIDExtra[EdgeDonor]); - AddExtra[EdgeDonor] = false; - - } - - } - - } - - else if (XcoordExtra.size() == 1) { - cout <<"There cutting system has failed, there is an incomplete curve (not used)." << endl; - } - - /*--- Find and add the trailing edge to to the list - and the contect the first point to the trailing edge ---*/ - - Trailing_Point = 0; Trailing_Coord = Xcoord_Index0[0]; - for (iEdge = 1; iEdge < Xcoord_Index0.size(); iEdge++) { - if (Xcoord_Index0[iEdge] > Trailing_Coord) { - Trailing_Point = iEdge; Trailing_Coord = Xcoord_Index0[iEdge]; - } - } - - Xcoord_Airfoil.push_back(Xcoord_Index0[Trailing_Point]); - Ycoord_Airfoil.push_back(Ycoord_Index0[Trailing_Point]); - Zcoord_Airfoil.push_back(Zcoord_Index0[Trailing_Point]); - Variable_Airfoil.push_back(Variable_Index0[Trailing_Point]); - IGlobalID_Airfoil.push_back(IGlobalID_Index0[Trailing_Point]); - JGlobalID_Airfoil.push_back(JGlobalID_Index0[Trailing_Point]); - - Xcoord_Airfoil.push_back(Xcoord_Index1[Trailing_Point]); - Ycoord_Airfoil.push_back(Ycoord_Index1[Trailing_Point]); - Zcoord_Airfoil.push_back(Zcoord_Index1[Trailing_Point]); - Variable_Airfoil.push_back(Variable_Index1[Trailing_Point]); - IGlobalID_Airfoil.push_back(IGlobalID_Index1[Trailing_Point]); - JGlobalID_Airfoil.push_back(JGlobalID_Index1[Trailing_Point]); - - Xcoord_Index0.erase (Xcoord_Index0.begin() + Trailing_Point); - Ycoord_Index0.erase (Ycoord_Index0.begin() + Trailing_Point); - Zcoord_Index0.erase (Zcoord_Index0.begin() + Trailing_Point); - Variable_Index0.erase (Variable_Index0.begin() + Trailing_Point); - IGlobalID_Index0.erase (IGlobalID_Index0.begin() + Trailing_Point); - JGlobalID_Index0.erase (JGlobalID_Index0.begin() + Trailing_Point); - - Xcoord_Index1.erase (Xcoord_Index1.begin() + Trailing_Point); - Ycoord_Index1.erase (Ycoord_Index1.begin() + Trailing_Point); - Zcoord_Index1.erase (Zcoord_Index1.begin() + Trailing_Point); - Variable_Index1.erase (Variable_Index1.begin() + Trailing_Point); - IGlobalID_Index1.erase (IGlobalID_Index1.begin() + Trailing_Point); - JGlobalID_Index1.erase (JGlobalID_Index1.begin() + Trailing_Point); - - - /*--- Algorithm for adding the rest of the points ---*/ - - do { - - /*--- Last added point in the list ---*/ - - Airfoil_Point = Xcoord_Airfoil.size() - 1; - - /*--- Find the closest point ---*/ - - Found_Edge = false; - - for (iEdge = 0; iEdge < Xcoord_Index0.size(); iEdge++) { - - if (((IGlobalID_Index0[iEdge] == IGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index0[iEdge] == JGlobalID_Airfoil[Airfoil_Point])) || - ((IGlobalID_Index0[iEdge] == JGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index0[iEdge] == IGlobalID_Airfoil[Airfoil_Point]))) { - Next_Edge = iEdge; Found_Edge = true; Index = 0; break; - } - - if (((IGlobalID_Index1[iEdge] == IGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index1[iEdge] == JGlobalID_Airfoil[Airfoil_Point])) || - ((IGlobalID_Index1[iEdge] == JGlobalID_Airfoil[Airfoil_Point]) && (JGlobalID_Index1[iEdge] == IGlobalID_Airfoil[Airfoil_Point]))) { - Next_Edge = iEdge; Found_Edge = true; Index = 1; break; - } - - } - - /*--- Add and remove the next point to the list and the next point in the edge ---*/ - - if (Found_Edge) { - - if (Index == 0) { - Xcoord_Airfoil.push_back(Xcoord_Index1[Next_Edge]); - Ycoord_Airfoil.push_back(Ycoord_Index1[Next_Edge]); - Zcoord_Airfoil.push_back(Zcoord_Index1[Next_Edge]); - Variable_Airfoil.push_back(Variable_Index1[Next_Edge]); - IGlobalID_Airfoil.push_back(IGlobalID_Index1[Next_Edge]); - JGlobalID_Airfoil.push_back(JGlobalID_Index1[Next_Edge]); - } - - if (Index == 1) { - Xcoord_Airfoil.push_back(Xcoord_Index0[Next_Edge]); - Ycoord_Airfoil.push_back(Ycoord_Index0[Next_Edge]); - Zcoord_Airfoil.push_back(Zcoord_Index0[Next_Edge]); - Variable_Airfoil.push_back(Variable_Index0[Next_Edge]); - IGlobalID_Airfoil.push_back(IGlobalID_Index0[Next_Edge]); - JGlobalID_Airfoil.push_back(JGlobalID_Index0[Next_Edge]); - } - - Xcoord_Index0.erase(Xcoord_Index0.begin() + Next_Edge); - Ycoord_Index0.erase(Ycoord_Index0.begin() + Next_Edge); - Zcoord_Index0.erase(Zcoord_Index0.begin() + Next_Edge); - Variable_Index0.erase(Variable_Index0.begin() + Next_Edge); - IGlobalID_Index0.erase(IGlobalID_Index0.begin() + Next_Edge); - JGlobalID_Index0.erase(JGlobalID_Index0.begin() + Next_Edge); - - Xcoord_Index1.erase(Xcoord_Index1.begin() + Next_Edge); - Ycoord_Index1.erase(Ycoord_Index1.begin() + Next_Edge); - Zcoord_Index1.erase(Zcoord_Index1.begin() + Next_Edge); - Variable_Index1.erase(Variable_Index1.begin() + Next_Edge); - IGlobalID_Index1.erase(IGlobalID_Index1.begin() + Next_Edge); - JGlobalID_Index1.erase(JGlobalID_Index1.begin() + Next_Edge); - - } - else { break; } - - } while (Xcoord_Index0.size() != 0); - - /*--- Clean the vector before using them again for storing the upper or the lower side ---*/ - - Xcoord_Index0.clear(); Ycoord_Index0.clear(); Zcoord_Index0.clear(); Variable_Index0.clear(); IGlobalID_Index0.clear(); JGlobalID_Index0.clear(); - Xcoord_Index1.clear(); Ycoord_Index1.clear(); Zcoord_Index1.clear(); Variable_Index1.clear(); IGlobalID_Index1.clear(); JGlobalID_Index1.clear(); - - } - - } - - AD_END_PASSIVE - -} - -void CGeometry::RegisterCoordinates(CConfig *config) { - unsigned short iDim; - unsigned long iPoint; - bool input = true; - bool push_index = config->GetMultizone_Problem()? false : true; - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - AD::RegisterInput(node[iPoint]->GetCoord()[iDim], push_index); - } - if(!push_index) { - for (iDim = 0; iDim < nDim; iDim++) { - node[iPoint]->SetIndex(input); - } - } - } -} - -void CGeometry::RegisterOutput_Coordinates(CConfig *config){ - unsigned short iDim; - unsigned long iPoint; - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - if(config->GetMultizone_Problem()) { - for (iDim = 0; iDim < nDim; iDim++) { -// In case we are dealing with mesh adjoints the following two lines might be needed -// AD::RegisterOutput(node[iPoint]->GetCoord()[iDim]); -// node[iPoint]->SetAdjIndices(false); - AD::RegisterOutput(node[iPoint]->GetCoord()[iDim]); - } - } - else { - for (iDim = 0; iDim < nDim; iDim++) { - AD::RegisterOutput(node[iPoint]->GetCoord()[iDim]); - } - } - } -} - -void CGeometry::UpdateGeometry(CGeometry **geometry_container, CConfig *config) { - - unsigned short iMesh; - - geometry_container[MESH_0]->InitiateComms(geometry_container[MESH_0], config, COORDINATES); - geometry_container[MESH_0]->CompleteComms(geometry_container[MESH_0], config, COORDINATES); - if (config->GetGrid_Movement()){ - geometry_container[MESH_0]->InitiateComms(geometry_container[MESH_0], config, GRID_VELOCITY); - geometry_container[MESH_0]->CompleteComms(geometry_container[MESH_0], config, GRID_VELOCITY); - } - - geometry_container[MESH_0]->SetCoord_CG(); - geometry_container[MESH_0]->SetControlVolume(config, UPDATE); - geometry_container[MESH_0]->SetBoundControlVolume(config, UPDATE); - geometry_container[MESH_0]->SetMaxLength(config); - - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - /*--- Update the control volume structures ---*/ - - geometry_container[iMesh]->SetControlVolume(config,geometry_container[iMesh-1], UPDATE); - geometry_container[iMesh]->SetBoundControlVolume(config,geometry_container[iMesh-1], UPDATE); - geometry_container[iMesh]->SetCoord(geometry_container[iMesh-1]); - - } - - if (config->GetKind_Solver() == DISC_ADJ_RANS || config->GetKind_Solver() == DISC_ADJ_INC_RANS) - geometry_container[MESH_0]->ComputeWall_Distance(config); - -} - -void CGeometry::SetCustomBoundary(CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex; - string Marker_Tag; - - /* --- Initialize quantities for customized boundary conditions. - * Custom values are initialized with the default values specified in the config (avoiding non physical values) --- */ - CustomBoundaryTemperature = new su2double*[nMarker]; - CustomBoundaryHeatFlux = new su2double*[nMarker]; - - for(iMarker=0; iMarker < nMarker; iMarker++){ - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - CustomBoundaryHeatFlux[iMarker] = NULL; - CustomBoundaryTemperature[iMarker] = NULL; - if(config->GetMarker_All_PyCustom(iMarker)){ - switch(config->GetMarker_All_KindBC(iMarker)){ - case HEAT_FLUX: - CustomBoundaryHeatFlux[iMarker] = new su2double[nVertex[iMarker]]; - for(iVertex=0; iVertex < nVertex[iMarker]; iVertex++){ - CustomBoundaryHeatFlux[iMarker][iVertex] = config->GetWall_HeatFlux(Marker_Tag); - } - break; - case ISOTHERMAL: - CustomBoundaryTemperature[iMarker] = new su2double[nVertex[iMarker]]; - for(iVertex=0; iVertex < nVertex[iMarker]; iVertex++){ - CustomBoundaryTemperature[iMarker][iVertex] = config->GetIsothermal_Temperature(Marker_Tag); - } - break; - case INLET_FLOW: - // This case is handled in the solver class. - break; - default: - cout << "WARNING: Marker " << Marker_Tag << " is not customizable. Using default behavior." << endl; - break; - } - } - } - -} - -void CGeometry::UpdateCustomBoundaryConditions(CGeometry **geometry_container, CConfig *config){ - - unsigned short iMGfine, iMGlevel, nMGlevel, iMarker; - - nMGlevel = config->GetnMGLevels(); - for (iMGlevel=1; iMGlevel <= nMGlevel; iMGlevel++){ - iMGfine = iMGlevel-1; - for(iMarker = 0; iMarker< config->GetnMarker_All(); iMarker++){ - if(config->GetMarker_All_PyCustom(iMarker)){ - switch(config->GetMarker_All_KindBC(iMarker)){ - case HEAT_FLUX: - geometry_container[iMGlevel]->SetMultiGridWallHeatFlux(geometry_container[iMGfine], iMarker); - break; - case ISOTHERMAL: - geometry_container[iMGlevel]->SetMultiGridWallTemperature(geometry_container[iMGfine], iMarker); - break; - // Inlet flow handled in solver class. - default: break; - } - } - } - } -} - - -void CGeometry::ComputeSurf_Straightness(CConfig *config, - bool print_on_screen) { - - bool RefUnitNormal_defined; - unsigned short iDim, - iMarker, - iMarker_Global, - nMarker_Global = config->GetnMarker_CfgFile(); - unsigned long iVertex; - constexpr passivedouble epsilon = 1.0e-6; - su2double Area; - string Local_TagBound, - Global_TagBound; - - vector Normal(nDim), - UnitNormal(nDim), - RefUnitNormal(nDim); - - /*--- Assume now that this boundary marker is straight. As soon as one - AreaElement is found that is not aligend with a Reference then it is - certain that the boundary marker is not straight and one can stop - searching. Another possibility is that this process doesn't own - any nodes of that boundary, in that case we also have to assume the - boundary is straight. - Any boundary type other than SYMMETRY_PLANE or EULER_WALL gets - the value false (or see cases specified in the conditional below) - which could be wrong. ---*/ - bound_is_straight.resize(nMarker); - fill(bound_is_straight.begin(), bound_is_straight.end(), true); - - /*--- Loop over all local markers ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - Local_TagBound = config->GetMarker_All_TagBound(iMarker); - - /*--- Marker has to be Symmetry or Euler. Additionally marker can't be a - moving surface and Grid Movement Elasticity is forbidden as well. All - other GridMovements are rigid. ---*/ - if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE || - config->GetMarker_All_KindBC(iMarker) == EULER_WALL) && - config->GetMarker_Moving_Bool(Local_TagBound) == false && - config->GetKind_GridMovement() != ELASTICITY) { - - /*--- Loop over all global markers, and find the local-global pair via - matching unique string tags. ---*/ - for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) { - - Global_TagBound = config->GetMarker_CfgFile_TagBound(iMarker_Global); - if (Local_TagBound == Global_TagBound) { - - RefUnitNormal_defined = false; - iVertex = 0; - - while(bound_is_straight[iMarker] == true && - iVertex < nVertex[iMarker]) { - - vertex[iMarker][iVertex]->GetNormal(Normal.data()); - UnitNormal = Normal; - - /*--- Compute unit normal. ---*/ - Area = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - Area += Normal[iDim]*Normal[iDim]; - Area = sqrt(Area); - - /*--- Negate for outward convention. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] /= -Area; - - /*--- Check if unit normal is within tolerance of the Reference unit normal. - Reference unit normal = first unit normal found. ---*/ - if(RefUnitNormal_defined) { - for (iDim = 0; iDim < nDim; iDim++) { - if( abs(RefUnitNormal[iDim] - UnitNormal[iDim]) > epsilon ) { - bound_is_straight[iMarker] = false; - break; - } - } - } else { - RefUnitNormal = UnitNormal; //deep copy of values - RefUnitNormal_defined = true; - } - - iVertex++; - }//while iVertex - }//if Local == Global - }//for iMarker_Global - } else { - /*--- Enforce default value: false ---*/ - bound_is_straight[iMarker] = false; - }//if sym or euler ... - }//for iMarker - - /*--- Communicate results and print on screen. ---*/ - if(print_on_screen) { - - /*--- Additional vector which can later be MPI::Allreduce(d) to pring the results - on screen as nMarker (local) can vary across ranks. Default 'true' as it can - happen that a local rank does not contain an element of each surface marker. ---*/ - vector bound_is_straight_Global(nMarker_Global, true); - /*--- Match local with global tag bound and fill a Global Marker vector. ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - Local_TagBound = config->GetMarker_All_TagBound(iMarker); - for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) { - Global_TagBound = config->GetMarker_CfgFile_TagBound(iMarker_Global); - - if(Local_TagBound == Global_TagBound) - bound_is_straight_Global[iMarker_Global] = bound_is_straight[iMarker]; - - }//for iMarker_Global - }//for iMarker - - vector Buff_Send_isStraight(nMarker_Global), - Buff_Recv_isStraight(nMarker_Global); - - /*--- Cast to int as std::vector can be a special construct. MPI handling using - is more straight-forward. ---*/ - for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) - Buff_Send_isStraight[iMarker_Global] = static_cast (bound_is_straight_Global[iMarker_Global]); - - /*--- Product of type (bool) is equivalnt to a 'logical and' ---*/ - SU2_MPI::Allreduce(Buff_Send_isStraight.data(), Buff_Recv_isStraight.data(), - nMarker_Global, MPI_INT, MPI_PROD, MPI_COMM_WORLD); - - /*--- Print results on screen. ---*/ - if(rank == MASTER_NODE) { - for (iMarker_Global = 0; iMarker_Global < nMarker_Global; iMarker_Global++) { - if (config->GetMarker_CfgFile_KindBC(config->GetMarker_CfgFile_TagBound(iMarker_Global)) == SYMMETRY_PLANE || - config->GetMarker_CfgFile_KindBC(config->GetMarker_CfgFile_TagBound(iMarker_Global)) == EULER_WALL) { - - cout << "Boundary marker " << config->GetMarker_CfgFile_TagBound(iMarker_Global) << " is"; - if(Buff_Recv_isStraight[iMarker_Global] == false) cout << " NOT"; - if(nDim == 2) cout << " a single straight." << endl; - if(nDim == 3) cout << " a single plane." << endl; - }//if sym or euler - }//for iMarker_Global - }//if rank==MASTER - }//if print_on_scren - -} - - -void CGeometry::ComputeSurf_Curvature(CConfig *config) { - unsigned short iMarker, iNeigh_Point, iDim, iNode, iNeighbor_Nodes, Neighbor_Node; - unsigned long Neighbor_Point, iVertex, iPoint, jPoint, iElem_Bound, iEdge, nLocalVertex, MaxLocalVertex , *Buffer_Send_nVertex, *Buffer_Receive_nVertex, TotalnPointDomain; - int iProcessor, nProcessor; - vector Point_NeighborList, Elem_NeighborList, Point_Triangle, Point_Edge, Point_Critical; - vector::iterator it; - su2double U[3] = {0.0,0.0,0.0}, V[3] = {0.0,0.0,0.0}, W[3] = {0.0,0.0,0.0}, Length_U, Length_V, Length_W, CosValue, Angle_Value, *K, *Angle_Defect, *Area_Vertex, *Angle_Alpha, *Angle_Beta, **NormalMeanK, MeanK, GaussK, MaxPrinK, cot_alpha, cot_beta, delta, X1, X2, X3, Y1, Y2, Y3, radius, *Buffer_Send_Coord, *Buffer_Receive_Coord, *Coord, Dist, MinDist, MaxK, MinK, SigmaK; - bool *Check_Edge; - - bool fea = ((config->GetKind_Solver()==FEM_ELASTICITY) || (config->GetKind_Solver()==DISC_ADJ_FEM)); - - /*--- Allocate surface curvature ---*/ - K = new su2double [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) K[iPoint] = 0.0; - - if (nDim == 2) { - - /*--- Loop over all the markers ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - - /*--- Loop through all marker vertices again, this time also - finding the neighbors of each node.---*/ - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - - if (node[iPoint]->GetDomain()) { - /*--- Loop through neighbors. In 2-D, there should be 2 nodes on either - side of this vertex that lie on the same surface. ---*/ - Point_Edge.clear(); - - for (iNeigh_Point = 0; iNeigh_Point < node[iPoint]->GetnPoint(); iNeigh_Point++) { - Neighbor_Point = node[iPoint]->GetPoint(iNeigh_Point); - - /*--- Check if this neighbor lies on the surface. If so, - add to the list of neighbors. ---*/ - if (node[Neighbor_Point]->GetPhysicalBoundary()) { - Point_Edge.push_back(Neighbor_Point); - } - - } - - if (Point_Edge.size() == 2) { - - /*--- Compute the curvature using three points ---*/ - X1 = node[iPoint]->GetCoord(0); - X2 = node[Point_Edge[0]]->GetCoord(0); - X3 = node[Point_Edge[1]]->GetCoord(0); - Y1 = node[iPoint]->GetCoord(1); - Y2 = node[Point_Edge[0]]->GetCoord(1); - Y3 = node[Point_Edge[1]]->GetCoord(1); - - radius = sqrt(((X2-X1)*(X2-X1) + (Y2-Y1)*(Y2-Y1))* - ((X2-X3)*(X2-X3) + (Y2-Y3)*(Y2-Y3))* - ((X3-X1)*(X3-X1) + (Y3-Y1)*(Y3-Y1)))/ - (2.0*fabs(X1*Y2+X2*Y3+X3*Y1-X1*Y3-X2*Y1-X3*Y2)+EPS); - - K[iPoint] = 1.0/radius; - node[iPoint]->SetCurvature(K[iPoint]); - } - - } - - } - - } - - } - - } - - else { - - Angle_Defect = new su2double [nPoint]; - Area_Vertex = new su2double [nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - Angle_Defect[iPoint] = 2*PI_NUMBER; - Area_Vertex[iPoint] = 0.0; - } - - Angle_Alpha = new su2double [nEdge]; - Angle_Beta = new su2double [nEdge]; - Check_Edge = new bool [nEdge]; - for (iEdge = 0; iEdge < nEdge; iEdge++) { - Angle_Alpha[iEdge] = 0.0; - Angle_Beta[iEdge] = 0.0; - Check_Edge[iEdge] = true; - } - - NormalMeanK = new su2double *[nPoint]; - for (iPoint = 0; iPoint < nPoint; iPoint++) { - NormalMeanK[iPoint] = new su2double [nDim]; - for (iDim = 0; iDim < nDim; iDim++) { - NormalMeanK[iPoint][iDim] = 0.0; - } - } - - /*--- Loop over all the markers ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - - /*--- Loop over all the boundary elements ---*/ - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - - /*--- Only triangles ---*/ - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { - - /*--- Loop over all the nodes of the boundary element ---*/ - for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { - - iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); - - Point_Triangle.clear(); - - for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { - Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); - Neighbor_Point = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); - Point_Triangle.push_back(Neighbor_Point); - } - - iEdge = FindEdge(Point_Triangle[0], Point_Triangle[1]); - - for (iDim = 0; iDim < nDim; iDim++) { - U[iDim] = node[Point_Triangle[0]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); - V[iDim] = node[Point_Triangle[1]]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim); - } - - W[0] = 0.5*(U[1]*V[2]-U[2]*V[1]); W[1] = -0.5*(U[0]*V[2]-U[2]*V[0]); W[2] = 0.5*(U[0]*V[1]-U[1]*V[0]); - - Length_U = 0.0; Length_V = 0.0; Length_W = 0.0; CosValue = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { Length_U += U[iDim]*U[iDim]; Length_V += V[iDim]*V[iDim]; Length_W += W[iDim]*W[iDim]; } - Length_U = sqrt(Length_U); Length_V = sqrt(Length_V); Length_W = sqrt(Length_W); - for (iDim = 0; iDim < nDim; iDim++) { U[iDim] /= Length_U; V[iDim] /= Length_V; CosValue += U[iDim]*V[iDim]; } - if (CosValue >= 1.0) CosValue = 1.0; - if (CosValue <= -1.0) CosValue = -1.0; - - Angle_Value = acos(CosValue); - Area_Vertex[iPoint] += Length_W; - Angle_Defect[iPoint] -= Angle_Value; - if (Angle_Alpha[iEdge] == 0.0) Angle_Alpha[iEdge] = Angle_Value; - else Angle_Beta[iEdge] = Angle_Value; - - } - } - } - } - } - - /*--- Compute mean curvature ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { - if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) { - for (iNode = 0; iNode < bound[iMarker][iElem_Bound]->GetnNodes(); iNode++) { - iPoint = bound[iMarker][iElem_Bound]->GetNode(iNode); - - for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem_Bound]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { - Neighbor_Node = bound[iMarker][iElem_Bound]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); - jPoint = bound[iMarker][iElem_Bound]->GetNode(Neighbor_Node); - - iEdge = FindEdge(iPoint, jPoint); - - if (Check_Edge[iEdge]) { - - Check_Edge[iEdge] = false; - - if (tan(Angle_Alpha[iEdge]) != 0.0) cot_alpha = 1.0/tan(Angle_Alpha[iEdge]); else cot_alpha = 0.0; - if (tan(Angle_Beta[iEdge]) != 0.0) cot_beta = 1.0/tan(Angle_Beta[iEdge]); else cot_beta = 0.0; - - /*--- iPoint, and jPoint ---*/ - for (iDim = 0; iDim < nDim; iDim++) { - if (Area_Vertex[iPoint] != 0.0) NormalMeanK[iPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[iPoint]->GetCoord(iDim) - node[jPoint]->GetCoord(iDim)) / Area_Vertex[iPoint]; - if (Area_Vertex[jPoint] != 0.0) NormalMeanK[jPoint][iDim] += 3.0 * (cot_alpha + cot_beta) * (node[jPoint]->GetCoord(iDim) - node[iPoint]->GetCoord(iDim)) / Area_Vertex[jPoint]; - } - } - - } - } - } - } - } - } - - /*--- Compute Gauss, mean, max and min principal curvature, - and set the list of critical points ---*/ - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - - if (node[iPoint]->GetDomain()) { - - if (Area_Vertex[iPoint] != 0.0) GaussK = 3.0*Angle_Defect[iPoint]/Area_Vertex[iPoint]; - else GaussK = 0.0; - - MeanK = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - MeanK += NormalMeanK[iPoint][iDim]*NormalMeanK[iPoint][iDim]; - MeanK = sqrt(MeanK); - - delta = max((MeanK*MeanK - GaussK), 0.0); - - MaxPrinK = MeanK + sqrt(delta); - - /*--- Store the curvature value ---*/ - K[iPoint] = MaxPrinK; - node[iPoint]->SetCurvature(K[iPoint]); - } - - } - } - } - - delete [] Angle_Defect; - delete [] Area_Vertex; - delete [] Angle_Alpha; - delete [] Angle_Beta; - delete [] Check_Edge; - - for (iPoint = 0; iPoint < nPoint; iPoint++) - delete [] NormalMeanK[iPoint]; - delete [] NormalMeanK; - - } - - /*--- Sharp edge detection is based in the statistical - distribution of the curvature ---*/ - - MaxK = K[0]; MinK = K[0]; MeanK = 0.0; TotalnPointDomain = 0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - MaxK = max(MaxK, fabs(K[iPoint])); - MinK = min(MinK, fabs(K[iPoint])); - MeanK += fabs(K[iPoint]); - TotalnPointDomain++; - } - } - } - } - -#ifdef HAVE_MPI - su2double MyMeanK = MeanK; MeanK = 0.0; - su2double MyMaxK = MaxK; MaxK = 0.0; - unsigned long MynPointDomain = TotalnPointDomain; TotalnPointDomain = 0; - SU2_MPI::Allreduce(&MyMeanK, &MeanK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MyMaxK, &MaxK, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&MynPointDomain, &TotalnPointDomain, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#endif - - /*--- Compute the mean ---*/ - MeanK /= su2double(TotalnPointDomain); - - /*--- Compute the standard deviation ---*/ - SigmaK = 0.0; - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - SigmaK += (fabs(K[iPoint]) - MeanK) * (fabs(K[iPoint]) - MeanK); - } - } - } - } - -#ifdef HAVE_MPI - su2double MySigmaK = SigmaK; SigmaK = 0.0; - SU2_MPI::Allreduce(&MySigmaK, &SigmaK, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); -#endif - - SigmaK = sqrt(SigmaK/su2double(TotalnPointDomain)); - - if ((rank == MASTER_NODE) && (!fea)) - cout << "Max K: " << MaxK << ". Mean K: " << MeanK << ". Standard deviation K: " << SigmaK << "." << endl; - - Point_Critical.clear(); - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - if (fabs(K[iPoint]) > MeanK + config->GetRefSharpEdges()*SigmaK) { - Point_Critical.push_back(iPoint); - } - } - } - } - } - - /*--- Variables and buffers needed for MPI ---*/ - -#ifdef HAVE_MPI - SU2_MPI::Comm_size(MPI_COMM_WORLD, &nProcessor); -#else - nProcessor = 1; -#endif - - Buffer_Send_nVertex = new unsigned long [1]; - Buffer_Receive_nVertex = new unsigned long [nProcessor]; - - /*--- Count the total number of critical edge nodes. ---*/ - - nLocalVertex = Point_Critical.size(); - Buffer_Send_nVertex[0] = nLocalVertex; - - /*--- Communicate to all processors the total number of critical edge nodes. ---*/ - -#ifdef HAVE_MPI - MaxLocalVertex = 0; - SU2_MPI::Allreduce(&nLocalVertex, &MaxLocalVertex, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); - SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#else - MaxLocalVertex = nLocalVertex; - Buffer_Receive_nVertex[0] = nLocalVertex; -#endif - - - /*--- Create and initialize to zero some buffers to hold the coordinates - of the boundary nodes that are communicated from each partition (all-to-all). ---*/ - - Buffer_Send_Coord = new su2double [MaxLocalVertex*nDim]; - Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex*nDim]; - -#ifdef HAVE_MPI - unsigned long nBuffer = MaxLocalVertex*nDim; -#endif - - for (iVertex = 0; iVertex < MaxLocalVertex; iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) { - Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; - } - } - - /*--- Retrieve and store the coordinates of the sharp edges boundary nodes on - the local partition and broadcast them to all partitions. ---*/ - - for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { - iPoint = Point_Critical[iVertex]; - for (iDim = 0; iDim < nDim; iDim++) - Buffer_Send_Coord[iVertex*nDim+iDim] = node[iPoint]->GetCoord(iDim); - } - -#ifdef HAVE_MPI - SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer, MPI_DOUBLE, MPI_COMM_WORLD); -#else - for (iVertex = 0; iVertex < Point_Critical.size(); iVertex++) { - for (iDim = 0; iDim < nDim; iDim++) { - Buffer_Receive_Coord[iVertex*nDim+iDim] = Buffer_Send_Coord[iVertex*nDim+iDim]; - } - } -#endif - - /*--- Loop over all interior mesh nodes on the local partition and compute - the distances to each of the no-slip boundary nodes in the entire mesh. - Store the minimum distance to the wall for each interior mesh node. ---*/ - - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - Coord = node[iPoint]->GetCoord(); - - MinDist = 1E20; - for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { - for (iVertex = 0; iVertex < Buffer_Receive_nVertex[iProcessor]; iVertex++) { - Dist = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - Dist += (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim])* - (Coord[iDim]-Buffer_Receive_Coord[(iProcessor*MaxLocalVertex+iVertex)*nDim+iDim]); - } - if (Dist!=0.0) Dist = sqrt(Dist); - else Dist = 0.0; - if (Dist < MinDist) MinDist = Dist; - } - } - node[iPoint]->SetSharpEdge_Distance(MinDist); - } - - /*--- Deallocate Max curvature ---*/ - delete[] K; - - /*--- Deallocate the buffers needed for the MPI communication. ---*/ - delete[] Buffer_Send_Coord; - delete[] Buffer_Receive_Coord; - delete[] Buffer_Send_nVertex; - delete[] Buffer_Receive_nVertex; - -} - -void CGeometry::FilterValuesAtElementCG(const vector &filter_radius, - const vector > &kernels, - const unsigned short search_limit, - const su2double *input_values, - su2double *output_values) const -{ - /*--- Apply a filter to "input_values". The filter is an averaging process over the neighbourhood - of each element, which is a circle in 2D and a sphere in 3D of radius "filter_radius". - The filter is characterized by its kernel, i.e. how the weights are computed. Multiple kernels - can be specified in which case they are applied sequentially (each one being applied to the - output values of the previous filter. ---*/ - - unsigned long iElem, iElem_global, limited_searches = 0; - - /*--- Initialize output values and check if we need to do any more work than that ---*/ - for (iElem=0; iElem neighbour_start; - long *neighbour_idx = NULL; - GetGlobalElementAdjacencyMatrix(neighbour_start,neighbour_idx); - - /*--- Element centroids and volumes ---*/ - su2double *cg_elem = new su2double [Global_nElemDomain*nDim], - *vol_elem = new su2double [Global_nElemDomain]; - - /*--- Initialize ---*/ - for(iElem=0; iElemGetGlobalIndex(); - for(unsigned short iDim=0; iDimGetCG(iDim); - vol_elem[iElem_global] = elem[iElem]->GetVolume(); - } -#ifdef HAVE_MPI - /*--- Share with all processors ---*/ - { - su2double *buffer = NULL, *tmp = NULL; - - buffer = new su2double [Global_nElemDomain*nDim]; - SU2_MPI::Allreduce(cg_elem,buffer,Global_nElemDomain*nDim,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - tmp = cg_elem; cg_elem = buffer; delete [] tmp; - - buffer = new su2double [Global_nElemDomain]; - SU2_MPI::Allreduce(vol_elem,buffer,Global_nElemDomain,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - tmp = vol_elem; vol_elem = buffer; delete [] tmp; - } - - /*--- Account for the duplication introduced by the halo elements and the - reduction using MPI_SUM, which is required to maintain differentiabillity. ---*/ - vector halo_detect(Global_nElemDomain); - { - vector buffer(Global_nElemDomain,0); - for(iElem=0; iElemGetGlobalIndex()] = 1; - MPI_Allreduce(buffer.data(),halo_detect.data(),Global_nElemDomain,MPI_CHAR,MPI_SUM,MPI_COMM_WORLD); - } - for(iElem=0; iElem is_neighbor(Global_nElemDomain,false); - - for (unsigned long iKernel=0; iKernelGetGlobalIndex()] = output_values[iElem]; -#ifdef HAVE_MPI - /*--- Share with all processors ---*/ - { - su2double *buffer = new su2double [Global_nElemDomain], *tmp = NULL; - SU2_MPI::Allreduce(work_values,buffer,Global_nElemDomain,MPI_DOUBLE,MPI_SUM,MPI_COMM_WORLD); - tmp = work_values; work_values = buffer; delete [] tmp; - } - /*--- Account for duplication ---*/ - for(iElem=0; iElemGetGlobalIndex(); - - /*--- Find the neighbours of iElem ---*/ - vector neighbours; - limited_searches += !GetRadialNeighbourhood(iElem_global, SU2_TYPE::GetValue(kernel_radius), - search_limit, neighbour_start, neighbour_idx, cg_elem, neighbours, is_neighbor); - - /*--- Apply the kernel ---*/ - su2double weight = 0.0, numerator = 0.0, denominator = 0.0; - - switch ( kernel_type ) { - /*--- distance-based kernels (weighted averages) ---*/ - case CONSTANT_WEIGHT_FILTER: case CONICAL_WEIGHT_FILTER: case GAUSSIAN_WEIGHT_FILTER: - - for (auto idx : neighbours) - { - su2double distance = 0.0; - for (unsigned short iDim=0; iDim0) - cout << "Warning: The filter radius was limited for " << limited_searches - << " elements (" << limited_searches/(0.01*Global_nElemDomain) << "%).\n"; - - delete [] neighbour_idx; - delete [] cg_elem; - delete [] vol_elem; - delete [] work_values; -} - -void CGeometry::GetGlobalElementAdjacencyMatrix(vector &neighbour_start, - long *&neighbour_idx) const -{ - if ( neighbour_idx != NULL ) - SU2_MPI::Error("neighbour_idx is expected to be NULL, stopping to avoid a potential memory leak",CURRENT_FUNCTION); - - unsigned long iElem, iElem_global; - - /*--- Determine how much space we need for the adjacency matrix by counting the - neighbours of each element, i.e. its number of faces---*/ - unsigned short *nFaces_elem = new unsigned short [Global_nElemDomain]; - - for(iElem=0; iElemGetGlobalIndex(); - nFaces_elem[iElem_global] = elem[iElem]->GetnFaces(); - } -#ifdef HAVE_MPI - /*--- Share with all processors ---*/ - { - unsigned short *buffer = new unsigned short [Global_nElemDomain], *tmp = NULL; - MPI_Allreduce(nFaces_elem,buffer,Global_nElemDomain,MPI_UNSIGNED_SHORT,MPI_MAX,MPI_COMM_WORLD); - /*--- swap pointers and delete old data to keep the same variable name after reduction ---*/ - tmp = nFaces_elem; nFaces_elem = buffer; delete [] tmp; - } -#endif +#include "../../include/geometry/CPhysicalGeometry.hpp" +#include "../../include/adt_structure.hpp" +#include "../../include/toolboxes/printing_toolbox.hpp" +#include "../../include/toolboxes/CLinearPartitioner.hpp" +#include "../../include/CSU2ASCIIMeshReaderFVM.hpp" +#include "../../include/CCGNSMeshReaderFVM.hpp" +#include "../../include/CRectangularMeshReaderFVM.hpp" +#include "../../include/CBoxMeshReaderFVM.hpp" - /*--- Vector with the addresses of the start of the neighbours of a given element. - This is generated by a cumulative sum of the neighbour count. ---*/ - neighbour_start.resize(Global_nElemDomain+1); - - neighbour_start[0] = 0; - for(iElem=0; iElemGetGlobalIndex(); - unsigned long start_pos = neighbour_start[iElem_global]; - - for(unsigned short iFace=0; iFaceGetnFaces(); ++iFace) - { - long neighbour = elem[iElem]->GetNeighbor_Elements(iFace); - - if ( neighbour>=0 ) { - neighbour_idx[start_pos+iFace] = elem[neighbour]->GetGlobalIndex(); - } - } - } -#ifdef HAVE_MPI - /*--- Share with all processors ---*/ - { - long *buffer = new long [matrix_size], *tmp = NULL; - MPI_Allreduce(neighbour_idx,buffer,matrix_size,MPI_LONG,MPI_MAX,MPI_COMM_WORLD); - tmp = neighbour_idx; neighbour_idx = buffer; delete [] tmp; - } +#include +#include +#include +#ifdef _MSC_VER +#include #endif -} - -bool CGeometry::GetRadialNeighbourhood(const unsigned long iElem_global, - const passivedouble radius, - size_t search_limit, - const vector &neighbour_start, - const long *neighbour_idx, - const su2double *cg_elem, - vector &neighbours, - vector &is_neighbor) const -{ - /*--- Validate inputs if we are debugging. ---*/ - assert(neighbour_start.size() == Global_nElemDomain+1 && - neighbour_idx != nullptr && cg_elem != nullptr && - is_neighbor.size() == Global_nElemDomain && "invalid inputs"); - - /*--- 0 search_limit means "unlimited" (it will probably - stop once it gathers the entire domain, probably). ---*/ - if (!search_limit) search_limit = numeric_limits::max(); - - /*--- Center of the search ---*/ - neighbours.clear(); - neighbours.push_back(iElem_global); - is_neighbor[iElem_global] = true; - - passivedouble X0[3] = {0.0, 0.0, 0.0}; - for (unsigned short iDim=0; iDim candidates; - - for (auto it = neighbours.begin()+start; it!=neighbours.end(); ++it) { - /*--- scan row of the adjacency matrix of element *it ---*/ - for (auto i = neighbour_start[*it]; i < neighbour_start[(*it)+1]; ++i) { - auto idx = neighbour_idx[i]; - if (idx>=0) if (!is_neighbor[idx]) { - candidates.push_back(idx); - /*--- mark as neighbour for now to avoid duplicate candidates. ---*/ - is_neighbor[idx] = true; - } - } - } - /*--- update start position to fetch next degree candidates. ---*/ - start = neighbours.size(); - - /*--- Add candidates within "radius" of X0, if none qualifies we are "finished". ---*/ - finished = true; - for (auto idx : candidates) - { - /*--- passivedouble as we only need to compare "distance". ---*/ - passivedouble distance = 0.0; - for (unsigned short iDim=0; iDimGetVTK_Type()) { - case TRIANGLE: element = elements[0]; break; - case QUADRILATERAL: element = elements[1]; break; - case TETRAHEDRON: element = elements[0]; break; - case PYRAMID: element = elements[1]; break; - case PRISM: element = elements[2]; break; - case HEXAHEDRON: element = elements[3]; break; - default: - SU2_MPI::Error("Cannot compute the area/volume of a 1D element.",CURRENT_FUNCTION); - } - /*--- Set the nodal coordinates of the element ---*/ - for (unsigned short iNode=0; iNodeGetnNodes(); ++iNode) { - unsigned long node_idx = elem[iElem]->GetNode(iNode); - for (unsigned short iDim=0; iDimGetCoord(iDim); - element->SetRef_Coord(iNode, iDim, coord); - } - } - /*--- Compute ---*/ - if(nDim==2) elem[iElem]->SetVolume(element->ComputeArea()); - else elem[iElem]->SetVolume(element->ComputeVolume()); - } - - delete elements[0]; - delete elements[1]; - if (nDim==3) { - delete elements[2]; - delete elements[3]; - } -} -void CGeometry::UpdateBoundaries(CConfig *config){ - - unsigned short iMarker; - unsigned long iElem_Surface, iNode_Surface, Point_Surface; - - for (iMarker = 0; iMarker GetnMarker_All(); iMarker++){ - for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { - for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { - - Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); - - node[Point_Surface]->SetPhysicalBoundary(false); - node[Point_Surface]->SetSolidBoundary(false); - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) - node[Point_Surface]->SetPhysicalBoundary(true); - - if (config->GetSolid_Wall(iMarker)) - node[Point_Surface]->SetSolidBoundary(true); - } - } - } - - /*--- Update the normal neighbors ---*/ - - FindNormal_Neighbor(config); - - /*--- Compute wall distance ---- */ - - ComputeWall_Distance(config); - -} CPhysicalGeometry::CPhysicalGeometry() : CGeometry() { - + size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); + rank = SU2_MPI::GetRank(); Local_to_Global_Point = NULL; Local_to_Global_Marker = NULL; @@ -3763,7 +53,7 @@ CPhysicalGeometry::CPhysicalGeometry() : CGeometry() { beg_node = NULL; end_node = NULL; - + nPointLinear = NULL; nPointCumulative = NULL; @@ -3773,7 +63,7 @@ CPhysicalGeometry::CPhysicalGeometry() : CGeometry() { xadj = NULL; #endif #endif - + /*--- Arrays for defining the turbomachinery structure ---*/ nSpanWiseSections = NULL; @@ -3803,27 +93,27 @@ CPhysicalGeometry::CPhysicalGeometry() : CGeometry() { } CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, unsigned short val_nZone) : CGeometry() { - + size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - + rank = SU2_MPI::GetRank(); + Local_to_Global_Point = NULL; Local_to_Global_Marker = NULL; Global_to_Local_Marker = NULL; - + beg_node = NULL; end_node = NULL; - + nPointLinear = NULL; nPointCumulative = NULL; - + #ifdef HAVE_MPI #ifdef HAVE_PARMETIS adjacency = NULL; xadj = NULL; #endif #endif - + /*--- Arrays for defining the turbomachinery structure ---*/ nSpanWiseSections = NULL; @@ -3858,7 +148,7 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, nZone = val_nZone; ofstream boundary_file; string Grid_Marker; - + string val_mesh_filename = config->GetMesh_FileName(); unsigned short val_format = config->GetMesh_FileFormat(); @@ -3873,7 +163,7 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, (config->GetKind_Solver() == DISC_ADJ_FEM_RANS)); /*--- Initialize counters for local/global points & elements ---*/ - + if( fem_solver ) { switch (val_format) { case SU2: @@ -3902,17 +192,17 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, } /*--- After reading the mesh, assert that the dimension is equal to 2 or 3. ---*/ - + assert((nDim == 2) || (nDim == 3)); - + /*--- Loop over the points element to re-scale the mesh, and plot it (only SU2_CFD) ---*/ - + if (config->GetKind_SU2() == SU2_CFD) { - + NewCoord = new su2double [nDim]; - + /*--- The US system uses feet, but SU2 assumes that the grid is in inches ---*/ - + if (config->GetSystemMeasurements() == US) { for (iPoint = 0; iPoint < nPoint; iPoint++) { for (iDim = 0; iDim < nDim; iDim++) { @@ -3921,13 +211,13 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, node[iPoint]->SetCoord(NewCoord); } } - + delete [] NewCoord; - + } - + /*--- If SU2_DEF then write a file with the boundary information ---*/ - + if ((config->GetKind_SU2() == SU2_DEF) && (rank == MASTER_NODE)) { string str = "boundary.dat"; @@ -3935,15 +225,15 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, str = config->GetMultizone_FileName(str, val_iZone, ".dat"); /*--- Open .su2 grid file ---*/ - + boundary_file.open(str.c_str(), ios::out); - + /*--- Loop through and write the boundary info ---*/ - + boundary_file << "NMARK= " << nMarker << endl; - + for (iMarker = 0; iMarker < nMarker; iMarker++) { - + Grid_Marker = config->GetMarker_All_TagBound(iMarker); boundary_file << "MARKER_TAG= " << Grid_Marker << endl; boundary_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; @@ -3960,7 +250,7 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, boundary_file << iElem_Bound << endl; } } - + if (nDim == 3) { for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { boundary_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; @@ -3973,13 +263,13 @@ CPhysicalGeometry::CPhysicalGeometry(CConfig *config, unsigned short val_iZone, boundary_file << iElem_Bound << endl; } } - + } - + boundary_file.close(); } - + } CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, @@ -4000,7 +290,7 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, beg_node = NULL; end_node = NULL; - + nPointLinear = NULL; nPointCumulative = NULL; @@ -4010,7 +300,7 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, xadj = NULL; #endif #endif - + /*--- Arrays for defining the turbomachinery structure ---*/ nSpanWiseSections = NULL; @@ -4028,7 +318,7 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, MaxAngularCoord = NULL; MinAngularCoord = NULL; MinRelAngularCoord = NULL; - + TangGridVelIn = NULL; SpanAreaIn = NULL; TurboRadiusIn = NULL; @@ -4104,7 +394,7 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, /*--- Recompute the linear partitioning offsets. ---*/ PrepareOffsets(geometry->GetGlobal_nPoint()); - + /*--- Communicate the coloring data so that each rank has a complete set of colors for all points that reside on it, including repeats. ---*/ @@ -4175,7 +465,7 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, #endif /*--- With the distribution of all points, elements, and markers based - on the ParMETIS coloring complete, as a final step, load this data into + on the ParMETIS coloring complete, as a final step, load this data into our geometry class data structures. ---*/ LoadPoints(config, geometry); @@ -4186,7 +476,7 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, Neighbors.clear(); Color_List.clear(); - + if (Local_Points != NULL) delete [] Local_Points; if (Local_Colors != NULL) delete [] Local_Colors; if (Local_Coords != NULL) delete [] Local_Coords; @@ -4232,11 +522,11 @@ CPhysicalGeometry::CPhysicalGeometry(CGeometry *geometry, } CPhysicalGeometry::~CPhysicalGeometry(void) { - + if (Local_to_Global_Point != NULL) delete [] Local_to_Global_Point; if (Global_to_Local_Marker != NULL) delete [] Global_to_Local_Marker; if (Local_to_Global_Marker != NULL) delete [] Local_to_Global_Marker; - + /*--- Free up memory from turbomachinery performance computation ---*/ unsigned short iMarker; @@ -4384,6 +674,13 @@ CPhysicalGeometry::~CPhysicalGeometry(void) { } +void CPhysicalGeometry::SetGlobal_to_Local_Point(void) { + Global_to_Local_Point.clear(); + for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + Global_to_Local_Point[node[iPoint]->GetGlobalIndex()] = iPoint; + } +} + void CPhysicalGeometry::DistributeColoring(CConfig *config, CGeometry *geometry) { @@ -4394,18 +691,18 @@ void CPhysicalGeometry::DistributeColoring(CConfig *config, unsigned short iNode, jNode; unsigned long iPoint, iNeighbor, jPoint, iElem, iProcessor; - + map Point_Map; map::iterator MI; - + vector::iterator it; SU2_MPI::Request *colorSendReq = NULL, *idSendReq = NULL; SU2_MPI::Request *colorRecvReq = NULL, *idRecvReq = NULL; int iProc, iSend, iRecv, myStart, myFinal; - + /*--- Get a linear partitioner to track the partition counts. ---*/ - + CLinearPartitioner pointPartitioner(geometry->GetGlobal_nPoint(),0); /*--- First, create a complete map of the points on this rank (excluding @@ -4435,9 +732,9 @@ void CPhysicalGeometry::DistributeColoring(CConfig *config, for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { Global2Local[geometry->node[iPoint]->GetGlobalIndex()] = iPoint; } - + /*--- Find extra points that carry an index higher than nPoint. ---*/ - + jPoint = geometry->GetnPoint(); for (MI = Point_Map.begin(); MI != Point_Map.end(); MI++) { iPoint = MI->first; @@ -5231,7 +1528,7 @@ void CPhysicalGeometry::DistributePoints(CConfig *config, CGeometry *geometry) { Local_Points = new unsigned long[nPoint_Recv[size]]; Local_Colors = new unsigned long[nPoint_Recv[size]]; Local_Coords = new su2double[nDim*nPoint_Recv[size]]; - + nLocal_PointDomain = 0; nLocal_PointGhost = 0; for (iRecv = 0; iRecv < nPoint_Recv[size]; iRecv++) { Local_Points[iRecv] = idRecv[iRecv]; @@ -5241,7 +1538,7 @@ void CPhysicalGeometry::DistributePoints(CConfig *config, CGeometry *geometry) { if (Local_Colors[iRecv] == (unsigned long)rank) nLocal_PointDomain++; else nLocal_PointGhost++; } - + /*--- Free temporary memory from communications ---*/ if (colorSendReq != NULL) delete [] colorSendReq; @@ -5261,7 +1558,7 @@ void CPhysicalGeometry::DistributePoints(CConfig *config, CGeometry *geometry) { delete [] nPoint_Recv; delete [] nPoint_Send; delete [] nPoint_Flag; - + } void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig *config, @@ -5463,12 +1760,12 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig *config, index[iProcessor] += NODES_PER_ELEMENT; markerIndex[iProcessor]++; } - + } } - + Global_Elem_Index++; - + } } @@ -5544,7 +1841,7 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig *config, idRecv[iRecv] = idSend[iSend]; iRecv++; } - + } /*--- Complete the non-blocking communications. ---*/ @@ -5619,7 +1916,7 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig *config, SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION); break; } - + /*--- Free temporary memory from communications ---*/ if (connSendReq != NULL) delete [] connSendReq; @@ -5633,7 +1930,7 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig *config, if (connSend != NULL) delete [] connSend; if (markerSend != NULL) delete [] markerSend; if (idSend != NULL) delete [] idSend; - + delete [] connRecv; delete [] markerRecv; delete [] idRecv; @@ -5641,7 +1938,7 @@ void CPhysicalGeometry::PartitionSurfaceConnectivity(CConfig *config, delete [] nElem_Recv; delete [] nElem_Send; delete [] nElem_Flag; - + } void CPhysicalGeometry::DistributeSurfaceConnectivity(CConfig *config, @@ -5825,7 +2122,7 @@ void CPhysicalGeometry::DistributeSurfaceConnectivity(CConfig *config, index[iProcessor] += NODES_PER_ELEMENT; markerIndex[iProcessor]++; - + } } } @@ -5968,7 +2265,7 @@ void CPhysicalGeometry::DistributeSurfaceConnectivity(CConfig *config, SU2_MPI::Error("Unrecognized element type.", CURRENT_FUNCTION); break; } - + /*--- Free temporary memory from communications ---*/ if (connSendReq != NULL) delete [] connSendReq; @@ -5988,7 +2285,7 @@ void CPhysicalGeometry::DistributeSurfaceConnectivity(CConfig *config, delete [] nElem_Recv; delete [] nElem_Send; delete [] nElem_Flag; - + } void CPhysicalGeometry::DistributeMarkerTags(CConfig *config, CGeometry *geometry) { @@ -6038,7 +2335,7 @@ void CPhysicalGeometry::DistributeMarkerTags(CConfig *config, CGeometry *geometr /*--- Free string buffer memory. ---*/ delete [] mpi_str_buf; - + } void CPhysicalGeometry::LoadPoints(CConfig *config, CGeometry *geometry) { @@ -6147,7 +2444,7 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) unsigned long iElem, jElem, kElem, iNode, Local_Elem, iGlobal_Index; unsigned long Local_Nodes[N_POINTS_HEXAHEDRON]; - + unsigned long iElemTria = 0; unsigned long iElemQuad = 0; unsigned long iElemTetr = 0; @@ -6247,11 +2544,11 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) } /*--- Free memory as we go. ---*/ - + Tria_List.clear(); for (it = Quad_List.begin(); it != Quad_List.end(); it++) { - + kElem = it->first; iElem = it->second; @@ -6282,9 +2579,9 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) /*--- Free memory as we go. ---*/ Quad_List.clear(); - + for (it = Tetr_List.begin(); it != Tetr_List.end(); it++) { - + kElem = it->first; iElem = it->second; @@ -6313,9 +2610,9 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) } /*--- Free memory as we go. ---*/ - + Tetr_List.clear(); - + for (it = Hexa_List.begin(); it != Hexa_List.end(); it++) { kElem = it->first; @@ -6350,11 +2647,11 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) } /*--- Free memory as we go. ---*/ - + Hexa_List.clear(); for (it = Pris_List.begin(); it != Pris_List.end(); it++) { - + kElem = it->first; iElem = it->second; @@ -6387,9 +2684,9 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) /*--- Free memory as we go. ---*/ Pris_List.clear(); - + for (it = Pyra_List.begin(); it != Pyra_List.end(); it++) { - + kElem = it->first; iElem = it->second; @@ -6403,23 +2700,23 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) } /*--- Create the element object. ---*/ - + elem[jElem] = new CPyramid(Local_Nodes[0], Local_Nodes[1], Local_Nodes[2], Local_Nodes[3], Local_Nodes[4]); - + elem[jElem]->SetGlobalIndex(kElem); /*--- Increment our local counters. ---*/ - + jElem++; iElemPyra++; - + } - + /*--- Free memory as we go. ---*/ - + Pyra_List.clear(); /*--- Communicate the number of each element type to all processors. These @@ -6435,7 +2732,7 @@ void CPhysicalGeometry::LoadVolumeElements(CConfig *config, CGeometry *geometry) if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) cout << Global_nElem << " interior elements including halo cells. " << endl; - /*--- Set the value of Global_nElemDomain (stored in the geometry + /*--- Set the value of Global_nElemDomain (stored in the geometry container that is passed in). ---*/ Global_nElemDomain = geometry->GetGlobal_nElemDomain(); @@ -6519,7 +2816,7 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry vector::iterator it; /*--- Compute how many markers we have local to this rank by looping - through the global marker numbers of each local surface element and + through the global marker numbers of each local surface element and counting the unique set. ---*/ for (iElem = 0; iElem < nLocal_Line; iElem++) { @@ -6659,7 +2956,7 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry Local_Nodes[1], 2); /*--- Increment our counters for this marker and element type. ---*/ - + nElemBound_Local[iMarker]++; iElem_Line++; Line_List[iMarker].push_back(Elem_ID_Line[iElem]); @@ -6692,7 +2989,7 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry Local_Nodes[2], 3); /*--- Increment our counters for this marker and element type. ---*/ - + nElemBound_Local[iMarker]++; iElem_Tria++; BoundTria_List[iMarker].push_back(Elem_ID_BoundTria[iElem]); @@ -6726,7 +3023,7 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry Local_Nodes[3], 3); /*--- Increment our counters for this marker and element type. ---*/ - + nElemBound_Local[iMarker]++; iElem_Quad++; BoundQuad_List[iMarker].push_back(Elem_ID_BoundQuad[iElem]); @@ -6760,9 +3057,9 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); } - + /*--- Initialize pointers for turbomachinery computations ---*/ - + nSpanWiseSections = new unsigned short[2]; nSpanSectionsByMarker = new unsigned short[nMarker]; SpanWiseValue = new su2double*[2]; @@ -6801,7 +3098,7 @@ void CPhysicalGeometry::LoadSurfaceElements(CConfig *config, CGeometry *geometry } /*--- Initialize pointers for turbomachinery performance computation ---*/ - + nTurboPerf = config->GetnMarker_TurboPerformance(); TangGridVelIn = new su2double*[config->GetnMarker_TurboPerformance()]; SpanAreaIn = new su2double*[config->GetnMarker_TurboPerformance()]; @@ -7000,36 +3297,36 @@ void CPhysicalGeometry::CompleteCommsAll(int nSends, for (iSend = 0; iSend < nSends; iSend++) SU2_MPI::Waitany(nSends, sendReq, &ind, &status); - + /*--- Wait for the non-blocking recvs to complete. ---*/ - + for (iRecv = 0; iRecv < nRecvs; iRecv++) SU2_MPI::Waitany(nRecvs, recvReq, &ind, &status); - + } void CPhysicalGeometry::PrepareOffsets(unsigned long val_npoint_global) { - + /*--- 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. ---*/ - + if (beg_node == NULL) beg_node = new unsigned long[size]; if (end_node == NULL) end_node = new unsigned long[size]; - + if (nPointLinear == NULL) nPointLinear = new unsigned long[size]; if (nPointCumulative == NULL) nPointCumulative = new unsigned long[size+1]; - + unsigned long quotient = val_npoint_global/size; int remainder = int(val_npoint_global%size); for (int ii = 0; ii < size; ii++) { nPointLinear[ii] = quotient + int(ii < remainder); } - + /*--- Store the local number of nodes on each proc in the linear partitioning, the beginning/end index, and the linear partitioning within an array in cumulative storage format. ---*/ - + beg_node[0] = 0; end_node[0] = beg_node[0] + nPointLinear[0]; nPointCumulative[0] = 0; @@ -7039,73 +3336,73 @@ void CPhysicalGeometry::PrepareOffsets(unsigned long val_npoint_global) { nPointCumulative[iProc] = nPointCumulative[iProc-1] + nPointLinear[iProc-1]; } nPointCumulative[size] = val_npoint_global; - + } unsigned long CPhysicalGeometry::GetLinearPartition(unsigned long val_global_index) { - + unsigned long iProcessor = 0; - + /*--- Initial guess ---*/ - + iProcessor = val_global_index/nPointLinear[0]; - + /*--- Guard against going over size. ---*/ - + if (iProcessor >= (unsigned long)size) iProcessor = (unsigned long)size-1; - + /*--- Move up or down until we find the processor. ---*/ - + if (val_global_index >= nPointCumulative[iProcessor]) while(val_global_index >= nPointCumulative[iProcessor+1]) iProcessor++; else while(val_global_index < nPointCumulative[iProcessor]) iProcessor--; - + return iProcessor; - + } void CPhysicalGeometry::SortAdjacency(CConfig *config) { - + #ifdef HAVE_MPI #ifdef HAVE_PARMETIS - + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) cout << "Executing the partitioning functions." << endl; - + /*--- Post process the adjacency information in order to get it into the CSR format before sending the data to ParMETIS. We need to remove repeats and adjust the size of the array for each local node. ---*/ - + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) cout << "Building the graph adjacency structure." << endl; - + /*--- Create a partitioner object so we can transform the global index values stored in the elements to a local index. ---*/ - + CLinearPartitioner pointPartitioner(Global_nPointDomain,0); - + /*--- We can already create the array that indexes the adjacency. ---*/ if (xadj == NULL) xadj = new idx_t[pointPartitioner.GetSizeOnRank(rank)+1]; xadj[0] = 0; - + /*--- Here, we transfer the adjacency information from a multi-dim vector on a node-by-node basis into a single vector container. First, we sort the entries and remove the duplicates we find for each node, then we copy it into the single vect and clear memory from the multi-dim vec. ---*/ - + unsigned long total_adj_size = 0; vector::iterator it; for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - + /*--- For each point, sort the adjacency in ascending order so that we can remove duplicates and complete the size for unique set of adjacent nodes for that point. ---*/ - + sort(adj_nodes[iPoint].begin(), adj_nodes[iPoint].end()); it = unique(adj_nodes[iPoint].begin(), adj_nodes[iPoint].end()); const unsigned long local_size = it - adj_nodes[iPoint].begin(); @@ -7116,40 +3413,40 @@ void CPhysicalGeometry::SortAdjacency(CConfig *config) { /*--- Now that we know the size, create the final adjacency array. This is the array that we will feed to ParMETIS for partitioning. ---*/ - + if (adjacency == NULL) adjacency = new idx_t[total_adj_size]; - + unsigned long kPoint = 0; for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - + /*--- Local size of the adjacency for the current point. ---*/ - + const unsigned long local_size = adj_nodes[iPoint].size(); - + /*--- Move the sorted adjacency into a 1-D vector for all points for loading into ParMETIS for partitioning next. ---*/ - + for (unsigned long jPoint = 0; jPoint < local_size; jPoint++) { adjacency[kPoint] = (idx_t)adj_nodes[iPoint][jPoint]; kPoint++; } - + /*--- Increment the starting index for the next point (CSR). ---*/ xadj[iPoint+1] = xadj[iPoint] + local_size; - + /*--- Free vector memory as we go. ---*/ - + vector().swap(adj_nodes[iPoint]); - + } /*--- Force free the entire old multi-dim. adjacency vector. ---*/ - + vector< vector >().swap(adj_nodes); #endif #endif - + } void CPhysicalGeometry::SetSendReceive(CConfig *config) { @@ -7161,11 +3458,11 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { unsigned long *nVertexDomain = new unsigned long[nMarker_Max]; unsigned short iNode, jNode; vector::iterator it; - - vector > SendTransfLocal; /*!< \brief Vector to store the type of transformation for this send point. */ - vector > ReceivedTransfLocal; /*!< \brief Vector to store the type of transformation for this received point. */ - vector > SendDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ - vector > ReceivedDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ + + vector > SendTransfLocal; /*!< \brief Vector to store the type of transformation for this send point. */ + vector > ReceivedTransfLocal; /*!< \brief Vector to store the type of transformation for this received point. */ + vector > SendDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ + vector > ReceivedDomainLocal; /*!< \brief SendDomain[from domain][to domain] and return the point index of the node that must me sended. */ map::const_iterator MI; @@ -7173,7 +3470,7 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { cout << "Establishing MPI communication patterns." << endl; nDomain = size; - + SendTransfLocal.resize(nDomain); ReceivedTransfLocal.resize(nDomain); SendDomainLocal.resize(nDomain); @@ -7188,28 +3485,28 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { iPoint = elem[iElem]->GetNode(iNode); iDomain = node[iPoint]->GetColor(); - + if (iDomain == (unsigned long) rank) { for (jNode = 0; jNode < elem[iElem]->GetnNodes(); jNode++) { jPoint = elem[iElem]->GetNode(jNode); jDomain = node[jPoint]->GetColor(); - - /*--- If one of the neighbors is a different color and connected + + /*--- If one of the neighbors is a different color and connected by an edge, then we add them to the list. ---*/ if (iDomain != jDomain) { - - /*--- We send from iDomain to jDomain the value of iPoint, + + /*--- We send from iDomain to jDomain the value of iPoint, we save the global value becuase we need to sort the lists. ---*/ SendDomainLocal[jDomain].push_back(Local_to_Global_Point[iPoint]); - /*--- We send from jDomain to iDomain the value of jPoint, + /*--- We send from jDomain to iDomain the value of jPoint, we save the global value becuase we need to sort the lists. ---*/ ReceivedDomainLocal[jDomain].push_back(Local_to_Global_Point[jPoint]); - + } } } @@ -7224,7 +3521,7 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { it = unique(SendDomainLocal[iDomain].begin(), SendDomainLocal[iDomain].end()); SendDomainLocal[iDomain].resize(it - SendDomainLocal[iDomain].begin()); } - + /*--- Sort the points that must be received and delete repeated points, note that the sorting should be done with the global point (not the local). ---*/ @@ -7233,7 +3530,7 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { it = unique( ReceivedDomainLocal[iDomain].begin(), ReceivedDomainLocal[iDomain].end()); ReceivedDomainLocal[iDomain].resize(it - ReceivedDomainLocal[iDomain].begin()); } - + /*--- Create Global to Local Point array, note that the array is smaller (Max_GlobalPoint) than the total number of points in the simulation ---*/ Max_GlobalPoint = 0; @@ -7246,19 +3543,19 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { for (iPoint = 0; iPoint < nPoint; iPoint++) Global_to_Local_Point[Local_to_Global_Point[iPoint]] = iPoint; - /*--- Add the new MPI send boundaries, reset the transformation, + /*--- Add the new MPI send boundaries, reset the transformation, and save the local value. ---*/ for (iDomain = 0; iDomain < nDomain; iDomain++) { if (SendDomainLocal[iDomain].size() != 0) { nVertexDomain[nMarker] = SendDomainLocal[iDomain].size(); for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) { - + MI = Global_to_Local_Point.find(SendDomainLocal[iDomain][iVertex]); if (MI != Global_to_Local_Point.end()) iPoint = Global_to_Local_Point[SendDomainLocal[iDomain][iVertex]]; else iPoint = -1; - + SendDomainLocal[iDomain][iVertex] = iPoint; SendTransfLocal[iDomain].push_back(0); } @@ -7267,18 +3564,18 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { nMarker++; } } - + /*--- Add the new MPI receive boundaries, reset the transformation, and save the local value ---*/ for (iDomain = 0; iDomain < nDomain; iDomain++) { if (ReceivedDomainLocal[iDomain].size() != 0) { nVertexDomain[nMarker] = ReceivedDomainLocal[iDomain].size(); for (iVertex = 0; iVertex < nVertexDomain[nMarker]; iVertex++) { - + MI = Global_to_Local_Point.find(ReceivedDomainLocal[iDomain][iVertex]); if (MI != Global_to_Local_Point.end()) iPoint = Global_to_Local_Point[ReceivedDomainLocal[iDomain][iVertex]]; else iPoint = -1; - + ReceivedDomainLocal[iDomain][iVertex] = iPoint; ReceivedTransfLocal[iDomain].push_back(0); } @@ -7292,10 +3589,10 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { Counter_Send = 0; Counter_Receive = 0; for (iDomain = 0; iDomain < nDomain; iDomain++) if (SendDomainLocal[iDomain].size() != 0) Counter_Send++; - + for (iDomain = 0; iDomain < nDomain; iDomain++) if (ReceivedDomainLocal[iDomain].size() != 0) Counter_Receive++; - + iMarkerSend = nMarker - Counter_Send - Counter_Receive; iMarkerReceive = nMarker - Counter_Receive; @@ -7324,7 +3621,7 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { iMarkerReceive++; } } - + /*--- Free memory ---*/ delete [] nVertexDomain; @@ -7332,37 +3629,38 @@ void CPhysicalGeometry::SetSendReceive(CConfig *config) { } void CPhysicalGeometry::SetBoundaries(CConfig *config) { - + unsigned long iElem_Bound, TotalElem, *nElem_Bound_Copy, iVertex_; string Grid_Marker; - unsigned short iDomain, nDomain, iMarkersDomain, iLoop, *DomainCount, nMarker_Physical, Duplicate_SendReceive, *DomainSendCount, **DomainSendMarkers, *DomainReceiveCount, **DomainReceiveMarkers, nMarker_SendRecv, iMarker, iMarker_; + unsigned short iDomain, nDomain, iMarkersDomain, iLoop, *DomainCount, nMarker_Physical, Duplicate_SendReceive, *DomainSendCount, + **DomainSendMarkers, *DomainReceiveCount, **DomainReceiveMarkers, nMarker_SendRecv, iMarker, iMarker_; CPrimalGrid*** bound_Copy; short *Marker_All_SendRecv_Copy; bool CheckStart; - + nDomain = size+1; - + /*--- Count the number of physical markers in the boundaries ---*/ - + nMarker_Physical = 0; for (iMarker = 0; iMarker < nMarker; iMarker++) { if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { nMarker_Physical++; } } - + /*--- Identify if there are markers that send/received with the same domain, they should be together---*/ - + Duplicate_SendReceive = 0; for (iLoop = 0; iLoop < 2; iLoop++) { - + DomainCount = new unsigned short [nDomain]; - + for (iDomain = 0; iDomain < nDomain; iDomain++) DomainCount[iDomain] = 0; - + if (iLoop == 0) { for (iDomain = 0; iDomain < nDomain; iDomain++) for (iMarker = 0; iMarker < nMarker; iMarker++) @@ -7375,27 +3673,27 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { if (bound[iMarker][0]->GetVTK_Type() == VERTEX) if (Marker_All_SendRecv[iMarker] == -iDomain) DomainCount[iDomain]++; } - + for (iDomain = 0; iDomain < nDomain; iDomain++) if (DomainCount[iDomain] > 1) Duplicate_SendReceive++; - + delete [] DomainCount; - + } - + DomainSendCount = new unsigned short [nDomain]; DomainSendMarkers = new unsigned short *[nDomain]; DomainReceiveCount = new unsigned short [nDomain]; DomainReceiveMarkers = new unsigned short *[nDomain]; - + for (iDomain = 0; iDomain < nDomain; iDomain++) { DomainSendCount[iDomain] = 0; DomainSendMarkers[iDomain] = new unsigned short [nMarker]; - + DomainReceiveCount[iDomain] = 0; DomainReceiveMarkers[iDomain] = new unsigned short [nMarker]; } - + for (iDomain = 0; iDomain < nDomain; iDomain++) { for (iMarker = 0; iMarker < nMarker; iMarker++) { if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { @@ -7410,10 +3708,10 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { } } } - + /*--- Create an structure to store the Send/Receive boundaries, because they require some reorganization ---*/ - + nMarker_SendRecv = nMarker - nMarker_Physical - Duplicate_SendReceive; bound_Copy = new CPrimalGrid**[nMarker_Physical + nMarker_SendRecv]; nElem_Bound_Copy = new unsigned long [nMarker_Physical + nMarker_SendRecv]; @@ -7421,21 +3719,21 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { iMarker_ = nMarker_Physical; iVertex_ = 0; CheckStart = false; - + /*--- Copy and allocate the physical markers in the data structure ---*/ - + for (iMarker = 0; iMarker < nMarker; iMarker++) { if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { - + nElem_Bound_Copy[iMarker] = nElem_Bound[iMarker]; bound_Copy[iMarker] = new CPrimalGrid* [nElem_Bound[iMarker]]; - + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { if (bound[iMarker][iElem_Bound]->GetVTK_Type() == LINE) bound_Copy[iMarker][iElem_Bound] = new CLine(bound[iMarker][iElem_Bound]->GetNode(0), bound[iMarker][iElem_Bound]->GetNode(1), 2); if (bound[iMarker][iElem_Bound]->GetVTK_Type() == TRIANGLE) - + bound_Copy[iMarker][iElem_Bound] = new CTriangle(bound[iMarker][iElem_Bound]->GetNode(0), bound[iMarker][iElem_Bound]->GetNode(1), bound[iMarker][iElem_Bound]->GetNode(2), 3); @@ -7447,13 +3745,13 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { } } } - - + + for (iDomain = 0; iDomain < nDomain; iDomain++) { - + /*--- Compute the total number of elements (adding all the boundaries with the same Send/Receive ---*/ - + if (DomainSendCount[iDomain] != 0) { TotalElem = 0; for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) { @@ -7466,22 +3764,22 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { nElem_Bound_Copy[iMarker_] = TotalElem; bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem]; } - + for (iMarkersDomain = 0; iMarkersDomain < DomainSendCount[iDomain]; iMarkersDomain++) { iMarker = DomainSendMarkers[iDomain][iMarkersDomain]; Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker]; - + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim); bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type()); iVertex_++; } - + } - + /*--- Compute the total number of elements (adding all the boundaries with the same Send/Receive ---*/ - + if (DomainReceiveCount[iDomain] != 0) { TotalElem = 0; for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) { @@ -7493,69 +3791,69 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { iVertex_ = 0; nElem_Bound_Copy[iMarker_] = TotalElem; bound_Copy[iMarker_] = new CPrimalGrid*[TotalElem]; - + } - + for (iMarkersDomain = 0; iMarkersDomain < DomainReceiveCount[iDomain]; iMarkersDomain++) { iMarker = DomainReceiveMarkers[iDomain][iMarkersDomain]; Marker_All_SendRecv_Copy[iMarker_] = Marker_All_SendRecv[iMarker]; - + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { bound_Copy[iMarker_][iVertex_] = new CVertexMPI(bound[iMarker][iElem_Bound]->GetNode(0), nDim); bound_Copy[iMarker_][iVertex_]->SetRotation_Type(bound[iMarker][iElem_Bound]->GetRotation_Type()); iVertex_++; } - + } - + } - + delete [] DomainSendCount; for (iDomain = 0; iDomain < nDomain; iDomain++) delete [] DomainSendMarkers[iDomain]; delete[] DomainSendMarkers; - + delete [] DomainReceiveCount; for (iDomain = 0; iDomain < nDomain; iDomain++) delete [] DomainReceiveMarkers[iDomain]; delete[] DomainReceiveMarkers; - + /*--- Deallocate the bound variables ---*/ - + for (iMarker = 0; iMarker < nMarker; iMarker++) { for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) if (bound[iMarker][iElem_Bound] != NULL) delete bound[iMarker][iElem_Bound]; if (bound[iMarker] != NULL) delete [] bound[iMarker]; } if (bound != NULL) delete [] bound; - + /*--- Allocate the new bound variables, and set the number of markers ---*/ - + bound = bound_Copy; nMarker = nMarker_Physical + nMarker_SendRecv; - + config->SetnMarker_All(nMarker); for (iMarker = 0; iMarker < nMarker; iMarker++) { nElem_Bound[iMarker] = nElem_Bound_Copy[iMarker]; } - for (iMarker = nMarker_Physical; iMarker < nMarker; iMarker++) { + for (iMarker = nMarker_Physical; iMarker < nMarker; iMarker++) { Marker_All_SendRecv[iMarker] = Marker_All_SendRecv_Copy[iMarker]; config->SetMarker_All_SendRecv(iMarker, Marker_All_SendRecv[iMarker]); config->SetMarker_All_TagBound(iMarker, "SEND_RECEIVE"); } - + /*--- Update config information storing the boundary information in the right place ---*/ - + for (iMarker = 0 ; iMarker < nMarker; iMarker++) { - + string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - + if (Marker_Tag != "SEND_RECEIVE") { - + /*--- 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_KindBC(iMarker, config->GetMarker_CfgFile_KindBC(Marker_Tag)); config->SetMarker_All_Monitoring(iMarker, config->GetMarker_CfgFile_Monitoring(Marker_Tag)); @@ -7570,22 +3868,22 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { 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_Turbomachinery(iMarker, config->GetMarker_CfgFile_Turbomachinery(Marker_Tag)); + 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)); } - + /*--- Send-Receive boundaries definition ---*/ - + else { - + config->SetMarker_All_KindBC(iMarker, SEND_RECEIVE); config->SetMarker_All_Monitoring(iMarker, NO); config->SetMarker_All_GeoEval(iMarker, NO); config->SetMarker_All_Designing(iMarker, NO); config->SetMarker_All_Plotting(iMarker, NO); config->SetMarker_All_Analyze(iMarker, NO); - config->SetMarker_All_ZoneInterface(iMarker, NO); + config->SetMarker_All_ZoneInterface(iMarker, NO); config->SetMarker_All_DV(iMarker, NO); config->SetMarker_All_Moving(iMarker, NO); config->SetMarker_All_Deform_Mesh(iMarker, NO); @@ -7595,19 +3893,19 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { config->SetMarker_All_Turbomachinery(iMarker, NO); config->SetMarker_All_TurbomachineryFlag(iMarker, NO); config->SetMarker_All_MixingPlaneInterface(iMarker, NO); - + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { if (config->GetMarker_All_SendRecv(iMarker) < 0) node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false); } - + } - + /*--- Loop over the surface element to set the boundaries ---*/ - + unsigned long Point_Surface, iElem_Surface; unsigned short iNode_Surface; - + for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { for (iNode_Surface = 0; iNode_Surface < bound[iMarker][iElem_Surface]->GetnNodes(); iNode_Surface++) { Point_Surface = bound[iMarker][iElem_Surface]->GetNode(iNode_Surface); @@ -7617,17 +3915,17 @@ void CPhysicalGeometry::SetBoundaries(CConfig *config) { config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) node[Point_Surface]->SetPhysicalBoundary(true); - + if (config->GetSolid_Wall(iMarker)) node[Point_Surface]->SetSolidBoundary(true); - + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) node[Point_Surface]->SetPeriodicBoundary(true); } } - + } - + delete [] Marker_All_SendRecv_Copy; delete [] nElem_Bound_Copy; } @@ -7636,9 +3934,9 @@ void CPhysicalGeometry::Read_Mesh_FVM(CConfig *config, string val_mesh_filename, unsigned short val_iZone, unsigned short val_nZone) { - + /*--- Initialize counters for local/global points & elements ---*/ - + Global_nPoint = 0; Global_nPointDomain = 0; Global_nElem = 0; Global_nElemDomain = 0; nelem_edge = 0; Global_nelem_edge = 0; @@ -7648,15 +3946,15 @@ void CPhysicalGeometry::Read_Mesh_FVM(CConfig *config, nelem_hexa = 0; Global_nelem_hexa = 0; nelem_prism = 0; Global_nelem_prism = 0; nelem_pyramid = 0; Global_nelem_pyramid = 0; - + /*--- Set the zone number from the input value. ---*/ - + nZone = val_nZone; - + /*--- Create a mesh reader to read a CGNS grid into linear partitions. ---*/ - + unsigned short val_format = config->GetMesh_FileFormat(); - + CMeshReaderFVM *MeshFVM = NULL; switch (val_format) { case SU2: @@ -7675,76 +3973,76 @@ void CPhysicalGeometry::Read_Mesh_FVM(CConfig *config, SU2_MPI::Error("Unrecognized mesh format specified!", CURRENT_FUNCTION); break; } - + /*--- Store the dimension of the problem ---*/ - + nDim = MeshFVM->GetDimension(); if (rank == MASTER_NODE) { if (nDim == 2) cout << "Two dimensional problem." << endl; if (nDim == 3) cout << "Three dimensional problem." << endl; } - + /*--- 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(); - + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) { cout << Global_nPoint << " grid points before partitioning." << endl; } else if (rank == MASTER_NODE) { cout << Global_nPoint << " grid points." << endl; } - + /*--- Store the local and global number of interior elements. ---*/ - + nElem = MeshFVM->GetNumberOfLocalElements(); Global_nElem = MeshFVM->GetNumberOfGlobalElements(); Global_nElemDomain = MeshFVM->GetNumberOfGlobalElements(); - + if ((rank == MASTER_NODE) && (size > SINGLE_NODE)) { cout << Global_nElem << " volume elements before partitioning." << endl; } else if (rank == MASTER_NODE) { 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. ---*/ - + LoadLinearlyPartitionedPoints(config, MeshFVM); LoadLinearlyPartitionedVolumeElements(config, MeshFVM); LoadUnpartitionedSurfaceElements(config, MeshFVM); - + /*--- Prepare the nodal adjacency structures for ParMETIS. ---*/ - + PrepareAdjacency(config); - + /*--- Now that we have loaded all information from the mesh, delete the mesh reader object. ---*/ - + if (MeshFVM != NULL) delete MeshFVM; - + } void CPhysicalGeometry::LoadLinearlyPartitionedPoints(CConfig *config, CMeshReaderFVM *mesh) { - + /*--- Get the linearly partitioned coordinates from the mesh object. ---*/ - + const vector > &gridCoords = mesh->GetLocalPointCoordinates(); - + /*--- Initialize point counts and the grid node data structure. ---*/ - + nPointNode = nPoint; node = new CPoint*[nPoint]; - + /*--- Loop over the CGNS grid nodes and load into the SU2 data structure. Note that since we have performed a linear partitioning of the grid nodes, we can simply initialize the global index to the first node that lies on our rank and increment. ---*/ - + CLinearPartitioner pointPartitioner(Global_nPointDomain,0); unsigned long GlobalIndex = pointPartitioner.GetFirstIndexOnRank(rank); for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { @@ -7766,53 +4064,53 @@ void CPhysicalGeometry::LoadLinearlyPartitionedPoints(CConfig *config, break; } } - + } void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *config, CMeshReaderFVM *mesh) { - + /*--- Reset the global to local element mapping. ---*/ - + Global_to_Local_Elem.clear(); - + /*--- Get the volume connectivity from the mesh object. ---*/ - + const vector &connElems = mesh->GetLocalVolumeElementConnectivity(); - + /*--- Allocate space for the CGNS interior elements in our SU2 data structure. Note that we only instantiate our rank's local set. ---*/ - + elem = new CPrimalGrid*[nElem]; - + /*--- Some temporaries for the loop below. ---*/ - + unsigned long Global_Index_Elem = 0, iElem = 0; vector connectivity(N_POINTS_HEXAHEDRON); - + /*--- Loop over all of the internal, local volumetric elements. ---*/ - + for (unsigned long jElem = 0; jElem < nElem; jElem++) { - + /*--- Get the global ID for this element. This is stored in the first entry of our connectivity stucture. ---*/ - + Global_Index_Elem = connElems[jElem*SU2_CONN_SIZE + 0]; - + /*--- Get the VTK type for this element. This is stored in the second entry of the connectivity structure. ---*/ - + int vtk_type = (int)connElems[jElem*SU2_CONN_SIZE + 1]; - + /*--- Instantiate this element in the proper SU2 data structure. During this loop, we also set the global to local element map for later use and increment the element counts for all types. ---*/ - + switch(vtk_type) { - + case TRIANGLE: - + for (unsigned long j = 0; j < N_POINTS_TRIANGLE; j++) { connectivity[j] = connElems[jElem*SU2_CONN_SIZE + SU2_CONN_SKIP + j]; } @@ -7822,9 +4120,9 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co connectivity[2], nDim); iElem++; nelem_triangle++; break; - + case QUADRILATERAL: - + for (unsigned long j = 0; j < N_POINTS_QUADRILATERAL; j++) { connectivity[j] = connElems[jElem*SU2_CONN_SIZE + SU2_CONN_SKIP + j]; } @@ -7835,9 +4133,9 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co connectivity[3], nDim); iElem++; nelem_quad++; break; - + case TETRAHEDRON: - + for (unsigned long j = 0; j < N_POINTS_TETRAHEDRON; j++) { connectivity[j] = connElems[jElem*SU2_CONN_SIZE + SU2_CONN_SKIP + j]; } @@ -7848,9 +4146,9 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co connectivity[3]); iElem++; nelem_tetra++; break; - + case HEXAHEDRON: - + for (unsigned long j = 0; j < N_POINTS_HEXAHEDRON; j++) { connectivity[j] = connElems[jElem*SU2_CONN_SIZE + SU2_CONN_SKIP + j]; } @@ -7865,9 +4163,9 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co connectivity[7]); iElem++; nelem_hexa++; break; - + case PRISM: - + for (unsigned long j = 0; j < N_POINTS_PRISM; j++) { connectivity[j] = connElems[jElem*SU2_CONN_SIZE + SU2_CONN_SKIP + j]; } @@ -7880,9 +4178,9 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co connectivity[5]); iElem++; nelem_prism++; break; - + case PYRAMID: - + for (unsigned long j = 0; j < N_POINTS_PYRAMID; j++) { connectivity[j] = connElems[jElem*SU2_CONN_SIZE + SU2_CONN_SKIP + j]; } @@ -7894,17 +4192,17 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co connectivity[4]); iElem++; nelem_pyramid++; break; - + default: SU2_MPI::Error("Element type not supported!", CURRENT_FUNCTION); break; } } - - + + /*--- Reduce the global counts of all element types found in the CGNS grid with all ranks. ---*/ - + #ifdef HAVE_MPI unsigned long Local_nElemTri = nelem_triangle; unsigned long Local_nElemQuad = nelem_quad; @@ -7932,95 +4230,95 @@ void CPhysicalGeometry::LoadLinearlyPartitionedVolumeElements(CConfig *co Global_nelem_prism = nelem_prism; Global_nelem_pyramid = nelem_pyramid; #endif - + } void CPhysicalGeometry::LoadUnpartitionedSurfaceElements(CConfig *config, CMeshReaderFVM *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 after we call ParMETIS. ---*/ - + if (rank == MASTER_NODE) { - + const vector §ionNames = mesh->GetMarkerNames(); - + /*--- Store the number of markers and print to the screen. ---*/ - + nMarker = mesh->GetNumberOfMarkers(); config->SetnMarker_All(nMarker); 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()]; - + /*--- Set some temporaries for the loop below. ---*/ - + int npe, vtk_type; unsigned long iElem = 0; vector connectivity(N_POINTS_HEXAHEDRON); - + /*--- Loop over all sections that we extracted from the CGNS 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++) { - + /*--- Initialize some counter variables ---*/ - + nelem_edge_bound = 0; nelem_triangle_bound = 0; nelem_quad_bound = 0; iElem = 0; - + /*--- Get the string name for this marker. ---*/ - + string Marker_Tag = sectionNames[iMarker]; - + /* Get the marker info and surface connectivity from the mesh object. */ - + const unsigned long surfElems = mesh->GetNumberOfSurfaceElementsForMarker(iMarker); - + const vector &connElems = mesh->GetSurfaceElementConnectivityForMarker(iMarker); - + /*--- Set the number of boundary elements in this marker. ---*/ - + nElem_Bound[iMarker] = surfElems; - + /*--- Report the number and name of the marker to the console. ---*/ - + cout << nElem_Bound[iMarker] << " boundary elements in index "; cout << iMarker <<" (Marker = " <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)); @@ -8063,168 +4361,168 @@ void CPhysicalGeometry::LoadUnpartitionedSurfaceElements(CConfig *config, 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::PrepareAdjacency(CConfig *config) { - + #ifdef HAVE_MPI #ifdef HAVE_PARMETIS - + /*--- Resize the vector for the adjacency information (ParMETIS). ---*/ - + adj_nodes.clear(); adj_nodes.resize(nPoint); for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) adj_nodes[iPoint].resize(0); - + /*--- Create a partitioner object so we can transform the global index values stored in the elements to a local index. ---*/ - + CLinearPartitioner pointPartitioner(Global_nPointDomain,0); const unsigned long firstIndex = pointPartitioner.GetFirstIndexOnRank(rank); - + /*--- Loop over all elements that are now loaded and store adjacency. ---*/ - + unsigned long connectivity[8] = {0,0,0,0,0,0,0,0}; for (unsigned long iElem = 0; iElem < nElem; iElem++) { - + /*--- Get the VTK type for this element. This is stored in the first entry of the connectivity structure. ---*/ - + unsigned short VTK_Type = elem[iElem]->GetVTK_Type(); - + /*--- Instantiate this element and build adjacency structure. ---*/ - + switch(VTK_Type) { - + case TRIANGLE: - + /*--- Store the connectivity for this element more easily. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_TRIANGLE; iNode++) { connectivity[iNode] = elem[iElem]->GetNode(iNode); } - + /*--- Decide whether we need to store the adjacency for any nodes in the current element, i.e., check if any of the nodes have a global index value within the range of our linear partitioning. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_TRIANGLE; iNode++) { - + const long local_index = connectivity[iNode]-firstIndex; - + if ((local_index >= 0) && (local_index < (long)nPoint)) { - + /*--- This node is within our linear partition. Add the neighboring nodes to this nodes' adjacency list. ---*/ - + for (unsigned long jNode = 0; jNode < N_POINTS_TRIANGLE; jNode++) { - + /*--- Build adjacency assuming the VTK connectivity ---*/ - + if (iNode != jNode) adj_nodes[local_index].push_back(connectivity[jNode]); - + } - + } } - + break; - + case QUADRILATERAL: - + /*--- Store the connectivity for this element more easily. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_QUADRILATERAL; iNode++) { connectivity[iNode] = elem[iElem]->GetNode(iNode); } - + /*--- Decide whether we need to store the adjacency for any nodes in the current element, i.e., check if any of the nodes have a global index value within the range of our linear partitioning. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_QUADRILATERAL; iNode++) { - + const long local_index = connectivity[iNode]-firstIndex; - + if ((local_index >= 0) && (local_index < (long)nPoint)) { - + /*--- This node is within our linear partition. Add the neighboring nodes to this nodes' adjacency list. ---*/ - + /*--- Build adjacency assuming the VTK connectivity ---*/ - + adj_nodes[local_index].push_back(connectivity[(iNode+1)%4]); adj_nodes[local_index].push_back(connectivity[(iNode+3)%4]); - + } } - + break; - + case TETRAHEDRON: - + /*--- Store the connectivity for this element more easily. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_TETRAHEDRON; iNode++) { connectivity[iNode] = elem[iElem]->GetNode(iNode); } - + /*--- Decide whether we need to store the adjacency for any nodes in the current element, i.e., check if any of the nodes have a global index value within the range of our linear partitioning. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_TETRAHEDRON; iNode++) { - + const long local_index = connectivity[iNode]-firstIndex; - + if ((local_index >= 0) && (local_index < (long)nPoint)) { - + /*--- This node is within our linear partition. Add the neighboring nodes to this nodes' adjacency list. ---*/ - + for (unsigned long jNode = 0; jNode < N_POINTS_TETRAHEDRON; jNode++) { - + /*--- Build adjacency assuming the VTK connectivity ---*/ - + if (iNode != jNode) adj_nodes[local_index].push_back(connectivity[jNode]); - + } - + } } - + break; - + case HEXAHEDRON: - + /*--- Store the connectivity for this element more easily. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_HEXAHEDRON; iNode++) { connectivity[iNode] = elem[iElem]->GetNode(iNode); } - + /*--- Decide whether we need to store the adjacency for any nodes in the current element, i.e., check if any of the nodes have a global index value within the range of our linear partitioning. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_HEXAHEDRON; iNode++) { - + const long local_index = connectivity[iNode]-firstIndex; - + if ((local_index >= 0) && (local_index < (long)nPoint)) { - + /*--- This node is within our linear partition. Add the neighboring nodes to this nodes' adjacency list. ---*/ - + /*--- Build adjacency assuming the VTK connectivity ---*/ - + if (iNode < 4) { adj_nodes[local_index].push_back(connectivity[(iNode+1)%4]); adj_nodes[local_index].push_back(connectivity[(iNode+3)%4]); @@ -8233,35 +4531,35 @@ void CPhysicalGeometry::PrepareAdjacency(CConfig *config) { adj_nodes[local_index].push_back(connectivity[(iNode-1)%4+4]); } adj_nodes[local_index].push_back(connectivity[(iNode+4)%8]); - + } } - + break; - + case PRISM: - + /*--- Store the connectivity for this element more easily. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_PRISM; iNode++) { connectivity[iNode] = elem[iElem]->GetNode(iNode); } - + /*--- Decide whether we need to store the adjacency for any nodes in the current element, i.e., check if any of the nodes have a global index value within the range of our linear partitioning. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_PRISM; iNode++) { - + const long local_index = connectivity[iNode]-firstIndex; - + if ((local_index >= 0) && (local_index < (long)nPoint)) { - + /*--- This node is within our linear partition. Add the neighboring nodes to this nodes' adjacency list. ---*/ - + /*--- Build adjacency assuming the VTK connectivity ---*/ - + if (iNode < 3) { adj_nodes[local_index].push_back(connectivity[(iNode+1)%3]); adj_nodes[local_index].push_back(connectivity[(iNode+2)%3]); @@ -8270,36 +4568,36 @@ void CPhysicalGeometry::PrepareAdjacency(CConfig *config) { adj_nodes[local_index].push_back(connectivity[(iNode-1)%3+3]); } adj_nodes[local_index].push_back(connectivity[(iNode+3)%6]); - + } } - + break; - + case PYRAMID: - - + + /*--- Store the connectivity for this element more easily. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_PYRAMID; iNode++) { connectivity[iNode] = elem[iElem]->GetNode(iNode); } - + /*--- Decide whether we need to store the adjacency for any nodes in the current element, i.e., check if any of the nodes have a global index value within the range of our linear partitioning. ---*/ - + for (unsigned long iNode = 0; iNode < N_POINTS_PYRAMID; iNode++) { - + const long local_index = connectivity[iNode]-firstIndex; - + if ((local_index >= 0) && (local_index < (long)nPoint)) { - + /*--- This node is within our linear partition. Add the neighboring nodes to this nodes' adjacency list. ---*/ - + /*--- Build adjacency assuming the VTK connectivity ---*/ - + if (iNode < 4) { adj_nodes[local_index].push_back(connectivity[(iNode+1)%4]); adj_nodes[local_index].push_back(connectivity[(iNode+3)%4]); @@ -8310,30 +4608,30 @@ void CPhysicalGeometry::PrepareAdjacency(CConfig *config) { adj_nodes[local_index].push_back(connectivity[2]); adj_nodes[local_index].push_back(connectivity[3]); } - + } } - + break; - + default: SU2_MPI::Error("Element type not supported!", CURRENT_FUNCTION); break; } } - + /*--- Prepare the adjacency information that ParMETIS will need for completing the graph partitioning in parallel. ---*/ - + SortAdjacency(config); - + #endif #endif - + } void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { - + unsigned long Point_1, Point_2, Point_3, Point_4, Point_5, Point_6, iElem, triangle_flip = 0, quad_flip = 0, tet_flip = 0, prism_flip = 0, hexa_flip = 0, pyram_flip = 0; @@ -8342,72 +4640,72 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { unsigned short iDim; /*--- Loop over all the elements ---*/ - + for (iElem = 0; iElem < nElem; iElem++) { - + /*--- 2D grid, triangle case ---*/ - + if (elem[iElem]->GetVTK_Type() == TRIANGLE) { - + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } test = a[0]*b[1]-b[0]*a[1]; - + if (test < 0.0) { elem[iElem]->Change_Orientation(); triangle_flip++; } } - + /*--- 2D grid, quadrilateral case ---*/ - + if (elem[iElem]->GetVTK_Type() == QUADRILATERAL) { - + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); } test_1 = a[0]*b[1]-b[0]*a[1]; - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_3[iDim]-Coord_2[iDim]); b[iDim] = 0.5*(Coord_4[iDim]-Coord_2[iDim]); } test_2 = a[0]*b[1]-b[0]*a[1]; - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_4[iDim]-Coord_3[iDim]); b[iDim] = 0.5*(Coord_1[iDim]-Coord_3[iDim]); } test_3 = a[0]*b[1]-b[0]*a[1]; - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_1[iDim]-Coord_4[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_4[iDim]); } test_4 = a[0]*b[1]-b[0]*a[1]; - + if ((test_1 < 0.0) && (test_2 < 0.0) && (test_3 < 0.0) && (test_4 < 0.0)) { elem[iElem]->Change_Orientation(); quad_flip++; } } - + /*--- 3D grid, tetrahedron case ---*/ - + if (elem[iElem]->GetVTK_Type() == TETRAHEDRON) { - + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8415,70 +4713,70 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; if (test < 0.0) { elem[iElem]->Change_Orientation(); tet_flip++; } - + } - + /*--- 3D grid, prism case ---*/ - + if (elem[iElem]->GetVTK_Type() == PRISM) { - + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(3); Coord_4 = node[Point_4]->GetCoord(); Point_5 = elem[iElem]->GetNode(4); Coord_5 = node[Point_5]->GetCoord(); Point_6 = elem[iElem]->GetNode(5); Coord_6 = node[Point_6]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); c[iDim] = (Coord_4[iDim]-Coord_1[iDim])+ (Coord_5[iDim]-Coord_2[iDim])+ (Coord_6[iDim]-Coord_3[iDim]); } - + /*--- The normal vector should point to the interior of the element ---*/ - + n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_5[iDim]-Coord_4[iDim]); b[iDim] = 0.5*(Coord_6[iDim]-Coord_4[iDim]); c[iDim] = (Coord_1[iDim]-Coord_4[iDim])+ (Coord_2[iDim]-Coord_5[iDim])+ (Coord_3[iDim]-Coord_6[iDim]); } - + /*--- The normal vector should point to the interior of the element ---*/ - + n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + if ((test_1 < 0.0) || (test_2 < 0.0)) { elem[iElem]->Change_Orientation(); prism_flip++; } - + } - + if (elem[iElem]->GetVTK_Type() == HEXAHEDRON) { - + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(5); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8486,14 +4784,14 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(7); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8501,14 +4799,14 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + Point_1 = elem[iElem]->GetNode(1); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(2); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(3); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(6); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8516,14 +4814,14 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_3 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + Point_1 = elem[iElem]->GetNode(3); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(0); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(1); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8531,24 +4829,24 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_4 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + if ((test_1 < 0.0) || (test_2 < 0.0) || (test_3 < 0.0) || (test_4 < 0.0)) { elem[iElem]->Change_Orientation(); hexa_flip++; } - + } - + if (elem[iElem]->GetVTK_Type() == PYRAMID) { - + Point_1 = elem[iElem]->GetNode(0); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(1); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(2); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8556,14 +4854,14 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_1 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + Point_1 = elem[iElem]->GetNode(2); Coord_1 = node[Point_1]->GetCoord(); Point_2 = elem[iElem]->GetNode(3); Coord_2 = node[Point_2]->GetCoord(); Point_3 = elem[iElem]->GetNode(0); Coord_3 = node[Point_3]->GetCoord(); Point_4 = elem[iElem]->GetNode(4); Coord_4 = node[Point_4]->GetCoord(); - + for (iDim = 0; iDim < nDim; iDim++) { a[iDim] = 0.5*(Coord_2[iDim]-Coord_1[iDim]); b[iDim] = 0.5*(Coord_3[iDim]-Coord_1[iDim]); @@ -8571,18 +4869,18 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { n[0] = a[1]*b[2]-b[1]*a[2]; n[1] = -(a[0]*b[2]-b[0]*a[2]); n[2] = a[0]*b[1]-b[0]*a[1]; - + test_2 = n[0]*c[0]+n[1]*c[1]+n[2]*c[2]; - + if ((test_1 < 0.0) || (test_2 < 0.0)) { elem[iElem]->Change_Orientation(); pyram_flip++; } - + } - + } - + #ifdef HAVE_MPI unsigned long Mytriangle_flip = triangle_flip; unsigned long Myquad_flip = quad_flip; @@ -8600,18 +4898,18 @@ void CPhysicalGeometry::Check_IntElem_Orientation(CConfig *config) { #endif if (rank == MASTER_NODE) { - if (triangle_flip > 0) cout << "There has been a re-orientation of the TRIANGLE volume elements." << endl; - if (quad_flip > 0) cout << "There has been a re-orientation of the QUADRILATERAL volume elements." << endl; - if (tet_flip > 0) cout << "There has been a re-orientation of the TETRAHEDRON volume elements." << endl; - if (prism_flip > 0) cout << "There has been a re-orientation of the PRISM volume elements." << endl; - if (hexa_flip > 0) cout << "There has been a re-orientation of the HEXAHEDRON volume elements." << endl; - if (pyram_flip > 0) cout << "There has been a re-orientation of the PYRAMID volume elements." << endl; + if (triangle_flip > 0) cout << "There has been a re-orientation of the TRIANGLE volume elements." << endl; + if (quad_flip > 0) cout << "There has been a re-orientation of the QUADRILATERAL volume elements." << endl; + if (tet_flip > 0) cout << "There has been a re-orientation of the TETRAHEDRON volume elements." << endl; + if (prism_flip > 0) cout << "There has been a re-orientation of the PRISM volume elements." << endl; + if (hexa_flip > 0) cout << "There has been a re-orientation of the HEXAHEDRON volume elements." << endl; + if (pyram_flip > 0) cout << "There has been a re-orientation of the PYRAMID volume elements." << endl; } } void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { - + unsigned long Point_1_Surface, Point_2_Surface, Point_3_Surface, Point_4_Surface, iElem_Domain, Point_Domain = 0, Point_Surface, iElem_Surface, line_flip = 0, triangle_flip = 0, quad_flip = 0; @@ -8621,11 +4919,11 @@ void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { bool find; for (iMarker = 0; iMarker < nMarker; iMarker++) { - + if (config->GetMarker_All_KindBC(iMarker) != INTERNAL_BOUNDARY) { - + for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { - + iElem_Domain = bound[iMarker][iElem_Surface]->GetDomainElement(); for (iNode_Domain = 0; iNode_Domain < elem[iElem_Domain]->GetnNodes(); iNode_Domain++) { Point_Domain = elem[iElem_Domain]->GetNode(iNode_Domain); @@ -8636,9 +4934,9 @@ void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { } if (!find) break; } - + /*--- 2D grid, line case ---*/ - + if (bound[iMarker][iElem_Surface]->GetVTK_Type() == LINE) { Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); @@ -8659,9 +4957,9 @@ void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { } } - + /*--- 3D grid, triangle case ---*/ - + if (bound[iMarker][iElem_Surface]->GetVTK_Type() == TRIANGLE) { Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); @@ -8688,9 +4986,9 @@ void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { } } - + /*--- 3D grid, rectangle case ---*/ - + if (bound[iMarker][iElem_Surface]->GetVTK_Type() == QUADRILATERAL) { Point_1_Surface = bound[iMarker][iElem_Surface]->GetNode(0); Coord_1 = node[Point_1_Surface]->GetCoord(); @@ -8763,9 +5061,9 @@ void CPhysicalGeometry::Check_BoundElem_Orientation(CConfig *config) { #endif if (rank == MASTER_NODE) { - if (line_flip > 0) cout << "There has been a re-orientation of the LINE surface elements." << endl; - if (triangle_flip > 0) cout << "There has been a re-orientation of the TRIANGLE surface elements." << endl; - if (quad_flip > 0) cout << "There has been a re-orientation of the QUADRILATERAL surface elements." << endl; + if (line_flip > 0) cout << "There has been a re-orientation of the LINE surface elements." << endl; + if (triangle_flip > 0) cout << "There has been a re-orientation of the TRIANGLE surface elements." << endl; + if (quad_flip > 0) cout << "There has been a re-orientation of the QUADRILATERAL surface elements." << endl; } } @@ -8819,7 +5117,7 @@ void CPhysicalGeometry::ComputeWall_Distance(CConfig *config) { VTK_TypeElem.push_back(VTK_Type); elemIDs.push_back(iElem); - for (unsigned short iNode = 0; iNode < nDOFsPerElem; iNode++) + for (unsigned short iNode = 0; iNode < nDOFsPerElem; iNode++) surfaceConn.push_back(bound[iMarker][iElem]->GetNode(iNode)); } } @@ -8872,10 +5170,10 @@ void CPhysicalGeometry::ComputeWall_Distance(CConfig *config) { if ( WallADT.IsEmpty() ) { - + /*--- No solid wall boundary nodes in the entire mesh. Set the wall distance to zero for all nodes. ---*/ - + for (unsigned long iPoint=0; iPointSetWall_Distance(0.0); } @@ -8883,19 +5181,19 @@ void CPhysicalGeometry::ComputeWall_Distance(CConfig *config) { /*--- Solid wall boundary nodes are present. Compute the wall distance for all nodes. ---*/ - + for (unsigned long iPoint=0; iPointGetCoord(), dist, markerID, elemID, rankID); node[iPoint]->SetWall_Distance(dist); } } - + } void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { @@ -8908,7 +5206,7 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { bool axisymmetric = config->GetAxisymmetric(); bool fea = ((config->GetKind_Solver() == FEM_ELASTICITY) || (config->GetKind_Solver() == DISC_ADJ_FEM)); - + PositiveXArea = 0.0; PositiveYArea = 0.0; PositiveZArea = 0.0; @@ -8917,7 +5215,7 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { for (iMarker = 0; iMarker < nMarker; iMarker++) { Boundary = config->GetMarker_All_KindBC(iMarker); Monitoring = config->GetMarker_All_Monitoring(iMarker); - + if ((((Boundary == EULER_WALL) || (Boundary == HEAT_FLUX) || (Boundary == ISOTHERMAL) || @@ -8943,7 +5241,7 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { if (Normal[0] < 0) PositiveXArea -= Normal[0]; if (Normal[1] < 0) PositiveYArea -= Normal[1]; if ((nDim == 3) && (Normal[2] < 0)) PositiveZArea -= Normal[2]; - + if (CoordX < MinCoordX) MinCoordX = CoordX; if (CoordX > MaxCoordX) MaxCoordX = CoordX; @@ -8954,21 +5252,21 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { if (CoordZ < MinCoordZ) MinCoordZ = CoordZ; if (CoordZ > MaxCoordZ) MaxCoordZ = CoordZ; } - + } } } - + #ifdef HAVE_MPI SU2_MPI::Allreduce(&PositiveXArea, &TotalPositiveXArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); SU2_MPI::Allreduce(&PositiveYArea, &TotalPositiveYArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); SU2_MPI::Allreduce(&PositiveZArea, &TotalPositiveZArea, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); - + SU2_MPI::Allreduce(&MinCoordX, &TotalMinCoordX, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); SU2_MPI::Allreduce(&MinCoordY, &TotalMinCoordY, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); SU2_MPI::Allreduce(&MinCoordZ, &TotalMinCoordZ, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); - + SU2_MPI::Allreduce(&MaxCoordX, &TotalMaxCoordX, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allreduce(&MaxCoordY, &TotalMaxCoordY, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allreduce(&MaxCoordZ, &TotalMaxCoordZ, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); @@ -8978,7 +5276,7 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { TotalPositiveXArea = PositiveXArea; TotalPositiveYArea = PositiveYArea; TotalPositiveZArea = PositiveZArea; - + TotalMinCoordX = MinCoordX; TotalMinCoordY = MinCoordY; TotalMinCoordZ = MinCoordZ; @@ -8989,14 +5287,14 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { TotalWettedArea = WettedArea; #endif - + /*--- Set a reference area if no value is provided ---*/ - + if (config->GetRefArea() == 0.0) { - + if (nDim == 3) config->SetRefArea(TotalPositiveZArea); else config->SetRefArea(TotalPositiveYArea); - + if (rank == MASTER_NODE) { if (nDim == 3) { cout << "Reference area = "<< TotalPositiveZArea; @@ -9007,23 +5305,23 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft." << endl; } } - + } - + /*--- Set a semi-span value if no value is provided ---*/ if (config->GetSemiSpan() == 0.0) { - + if (nDim == 3) config->SetSemiSpan(fabs(TotalMaxCoordY)); else config->SetSemiSpan(1.0); - + if ((nDim == 3) && (rank == MASTER_NODE)) { cout << "Semi-span length = "<< TotalMaxCoordY; if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft." << endl; } - + } - + if (rank == MASTER_NODE) { if (fea) cout << "Surface area = "<< TotalWettedArea; @@ -9042,25 +5340,25 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { if (nDim == 3) { cout << " z-plane = "<< TotalPositiveZArea; if (config->GetSystemMeasurements() == SI) cout <<" m^2." << endl; else cout <<" ft^2."<< endl; } - + cout << "Max. coordinate in the x-direction = "<< TotalMaxCoordX; if (config->GetSystemMeasurements() == SI) cout <<" m,"; else cout <<" ft,"; - + cout << " y-direction = "<< TotalMaxCoordY; if (config->GetSystemMeasurements() == SI) cout <<" m"; else cout <<" ft"; - + if (nDim == 3) { cout << ", z-direction = "<< TotalMaxCoordZ; if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft."<< endl; } else cout << "." << endl; - + cout << "Min. coordinate in the x-direction = "<< TotalMinCoordX; if (config->GetSystemMeasurements() == SI) cout <<" m,"; else cout <<" ft"; - + cout << " y-direction = "<< TotalMinCoordY; if (config->GetSystemMeasurements() == SI) cout <<" m"; else cout <<" ft"; - + if (nDim == 3) { cout << ", z-direction = "<< TotalMinCoordZ; if (config->GetSystemMeasurements() == SI) cout <<" m." << endl; else cout <<" ft."<< endl; @@ -9068,62 +5366,62 @@ void CPhysicalGeometry::SetPositive_ZArea(CConfig *config) { else cout << "." << endl; } - + } void CPhysicalGeometry::SetPoint_Connectivity(void) { - + unsigned short Node_Neighbor, iNode, iNeighbor; unsigned long jElem, Point_Neighbor, iPoint, iElem; - + /*--- Loop over all the elements ---*/ - + for (iElem = 0; iElem < nElem; iElem++) - + /*--- Loop over all the nodes of an element ---*/ - + for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { iPoint = elem[iElem]->GetNode(iNode); - + /*--- Store the element into the point ---*/ - + node[iPoint]->SetElem(iElem); } /*--- Loop over all the points ---*/ - + for (iPoint = 0; iPoint < nPoint; iPoint++) - + /*--- Loop over all elements shared by the point ---*/ - + for (iElem = 0; iElem < node[iPoint]->GetnElem(); iElem++) { - + jElem = node[iPoint]->GetElem(iElem); - + /*--- If we find the point iPoint in the surronding element ---*/ - + for (iNode = 0; iNode < elem[jElem]->GetnNodes(); iNode++) - + if (elem[jElem]->GetNode(iNode) == iPoint) - + /*--- Localize the local index of the neighbor of iPoint in the element ---*/ - + for (iNeighbor = 0; iNeighbor < elem[jElem]->GetnNeighbor_Nodes(iNode); iNeighbor++) { Node_Neighbor = elem[jElem]->GetNeighbor_Nodes(iNode, iNeighbor); Point_Neighbor = elem[jElem]->GetNode(Node_Neighbor); - + /*--- Store the point into the point ---*/ - + node[iPoint]->SetPoint(Point_Neighbor); } } - + /*--- Set the number of neighbors variable, this is important for JST and multigrid in parallel ---*/ - + for (iPoint = 0; iPoint < nPoint; iPoint++) node[iPoint]->SetnNeighbor(node[iPoint]->GetnPoint()); - + } void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { @@ -9131,32 +5429,32 @@ void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { vector Queue, AuxQueue, Result; unsigned short Degree, MinDegree, iDim, iMarker; bool *inQueue; - + inQueue = new bool [nPoint]; - + for (iPoint = 0; iPoint < nPoint; iPoint++) inQueue[iPoint] = false; - + /*--- Select the node with the lowest degree in the grid. ---*/ - + MinDegree = node[0]->GetnNeighbor(); AddPoint = 0; for (iPoint = 1; iPoint < nPointDomain; iPoint++) { Degree = node[iPoint]->GetnPoint(); if (Degree < MinDegree) { MinDegree = Degree; AddPoint = iPoint; } } - + /*--- Add the node in the first free position. ---*/ - + Result.push_back(AddPoint); inQueue[AddPoint] = true; - + /*--- Loop until reorganize all the nodes ---*/ - + do { - + /*--- Add to the queue all the nodes adjacent in the increasing order of their degree, checking if the element is already in the Queue. ---*/ - + AuxQueue.clear(); for (iNode = 0; iNode < node[AddPoint]->GetnPoint(); iNode++) { AdjPoint = node[AddPoint]->GetPoint(iNode); @@ -9164,11 +5462,11 @@ void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { AuxQueue.push_back(AdjPoint); } } - + if (AuxQueue.size() != 0) { - + /*--- Sort the auxiliar queue based on the number of neighbors ---*/ - + for (iNode = 0; iNode < AuxQueue.size(); iNode++) { for (jNode = 0; jNode < AuxQueue.size() - 1 - iNode; jNode++) { if (node[AuxQueue[jNode]]->GetnPoint() > node[AuxQueue[jNode+1]]->GetnPoint()) { @@ -9178,47 +5476,47 @@ void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { } } } - + Queue.insert(Queue.end(), AuxQueue.begin(), AuxQueue.end()); for (iNode = 0; iNode < AuxQueue.size(); iNode++) { inQueue[AuxQueue[iNode]] = true; } - + } - + /*--- Extract the first node from the queue and add it in the first free position. ---*/ - + if (Queue.size() != 0) { AddPoint = Queue[0]; Result.push_back(Queue[0]); Queue.erase (Queue.begin(), Queue.begin()+1); } - + /*--- Add to the queue all the nodes adjacent in the increasing order of their degree, checking if the element is already in the Queue. ---*/ - + } while (Queue.size() != 0); - + /*--- Check that all the points have been added ---*/ - + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { if (inQueue[iPoint] == false) Result.push_back(iPoint); } - + delete[] inQueue; - + reverse(Result.begin(), Result.end()); - + /*--- Add the MPI points ---*/ - + for (iPoint = nPointDomain; iPoint < nPoint; iPoint++) { Result.push_back(iPoint); } - + /*--- Reset old data structures ---*/ - + for (iPoint = 0; iPoint < nPoint; iPoint++) { node[iPoint]->ResetElem(); node[iPoint]->ResetPoint(); @@ -9228,52 +5526,52 @@ void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { node[iPoint]->SetPeriodicBoundary(false); node[iPoint]->SetDomain(true); } - + /*--- Set the new coordinates ---*/ - + su2double **AuxCoord; unsigned long *AuxGlobalIndex; - + AuxGlobalIndex = new unsigned long [nPoint]; AuxCoord = new su2double* [nPoint]; for (iPoint = 0; iPoint < nPoint; iPoint++) AuxCoord[iPoint] = new su2double [nDim]; - + for (iPoint = 0; iPoint < nPoint; iPoint++) { AuxGlobalIndex[iPoint] = node[iPoint]->GetGlobalIndex(); for (iDim = 0; iDim < nDim; iDim++) { AuxCoord[iPoint][iDim] = node[iPoint]->GetCoord(iDim); } } - + for (iPoint = 0; iPoint < nPoint; iPoint++) { node[iPoint]->SetGlobalIndex(AuxGlobalIndex[Result[iPoint]]); for (iDim = 0; iDim < nDim; iDim++) node[iPoint]->SetCoord(iDim, AuxCoord[Result[iPoint]][iDim]); } - + for (iPoint = 0; iPoint < nPoint; iPoint++) delete[] AuxCoord[iPoint]; delete[] AuxCoord; delete[] AuxGlobalIndex; - + /*--- Set the new conectivities ---*/ - + unsigned long *InvResult; InvResult = new unsigned long [nPoint]; for (iPoint = 0; iPoint < nPoint; iPoint++) InvResult[Result[iPoint]] = iPoint; - + for (iElem = 0; iElem < nElem; iElem++) { for (iNode = 0; iNode < elem[iElem]->GetnNodes(); iNode++) { iPoint = elem[iElem]->GetNode(iNode); elem[iElem]->SetNode(iNode, InvResult[iPoint]); } } - + for (iMarker = 0; iMarker < nMarker; iMarker++) { for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { - + string Marker_Tag = config->GetMarker_All_TagBound(iMarker); if (Marker_Tag == "SEND_RECEIVE") { for (unsigned long iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { @@ -9281,7 +5579,7 @@ void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { node[bound[iMarker][iElem_Bound]->GetNode(0)]->SetDomain(false); } } - + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { iPoint = bound[iMarker][iElem]->GetNode(iNode); bound[iMarker][iElem]->SetNode(iNode, InvResult[iPoint]); @@ -9292,52 +5590,52 @@ void CPhysicalGeometry::SetRCM_Ordering(CConfig *config) { config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY && config->GetMarker_All_KindBC(iMarker) != PERIODIC_BOUNDARY) node[InvResult[iPoint]]->SetPhysicalBoundary(true); - + if (config->GetMarker_All_KindBC(iMarker) == EULER_WALL || config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX || config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) node[InvResult[iPoint]]->SetSolidBoundary(true); - + if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) node[InvResult[iPoint]]->SetPeriodicBoundary(true); } } } - - + + delete[] InvResult; - + } void CPhysicalGeometry::SetElement_Connectivity(void) { unsigned short first_elem_face, second_elem_face, iFace, iNode, jElem; unsigned long face_point, Test_Elem, iElem; - + /*--- Loop over all the elements, faces and nodes ---*/ - + for (iElem = 0; iElem < nElem; iElem++) for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) for (iNode = 0; iNode < elem[iElem]->GetnNodesFace(iFace); iNode++) { face_point = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iNode)); - + /*--- Loop over all elements sharing the face point ---*/ - + for (jElem = 0; jElem < node[face_point]->GetnElem(); jElem++) { Test_Elem = node[face_point]->GetElem(jElem); - + /*--- If it is a new element in this face ---*/ - + if ((elem[iElem]->GetNeighbor_Elements(iFace) == -1) && (iElem < Test_Elem) && (FindFace(iElem, Test_Elem, first_elem_face, second_elem_face))) { - + /*--- Localice which faces are sharing both elements ---*/ - + elem[iElem]->SetNeighbor_Elements(Test_Elem, first_elem_face); - + /*--- Store the element for both elements ---*/ - + elem[Test_Elem]->SetNeighbor_Elements(iElem, second_elem_face); - + } } } @@ -9347,14 +5645,14 @@ void CPhysicalGeometry::SetBoundVolume(void) { unsigned short cont, iMarker, iElem, iNode_Domain, iNode_Surface; unsigned long Point_Domain, Point_Surface, Point, iElem_Surface, iElem_Domain; bool CheckVol; - + for (iMarker = 0; iMarker < nMarker; iMarker++) for (iElem_Surface = 0; iElem_Surface < nElem_Bound[iMarker]; iElem_Surface++) { - + /*--- Choose and arbitrary point from the surface --*/ Point = bound[iMarker][iElem_Surface]->GetNode(0); CheckVol = false; - + for (iElem = 0; iElem < node[Point]->GetnElem(); iElem++) { /*--- Look for elements surronding that point --*/ cont = 0; iElem_Domain = node[Point]->GetElem(iElem); @@ -9367,7 +5665,7 @@ void CPhysicalGeometry::SetBoundVolume(void) { } if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) break; } - + if (cont == bound[iMarker][iElem_Surface]->GetnNodes()) { bound[iMarker][iElem_Surface]->SetDomainElement(iElem_Domain); CheckVol = true; @@ -9385,60 +5683,60 @@ void CPhysicalGeometry::SetBoundVolume(void) { void CPhysicalGeometry::SetVertex(CConfig *config) { unsigned long iPoint, iVertex, iElem; unsigned short iMarker, iNode; - + /*--- Initialize the Vertex vector for each node of the grid ---*/ - + for (iPoint = 0; iPoint < nPoint; iPoint++) for (iMarker = 0; iMarker < nMarker; iMarker++) node[iPoint]->SetVertex(-1, iMarker); - + /*--- Create and compute the vector with the number of vertex per marker ---*/ - + nVertex = new unsigned long [nMarker]; for (iMarker = 0; iMarker < nMarker; iMarker++) { - + /*--- Initialize the number of Bound Vertex for each Marker ---*/ - + nVertex[iMarker] = 0; for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { iPoint = bound[iMarker][iElem]->GetNode(iNode); - + /*--- Set the vertex in the node information ---*/ - + if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) { node[iPoint]->SetVertex(nVertex[iMarker], iMarker); nVertex[iMarker]++; } } } - + /*--- Initialize the Vertex vector for each node, the previous result is deleted ---*/ - + for (iPoint = 0; iPoint < nPoint; iPoint++) for (iMarker = 0; iMarker < nMarker; iMarker++) node[iPoint]->SetVertex(-1, iMarker); - + /*--- Create the bound vertex structure, note that the order is the same as in the input file, this is important for Send/Receive part ---*/ - + vertex = new CVertex**[nMarker]; for (iMarker = 0; iMarker < nMarker; iMarker++) { vertex[iMarker] = new CVertex* [nVertex[iMarker]]; nVertex[iMarker] = 0; - + /*--- Initialize the number of Bound Vertex for each Marker ---*/ - + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { iPoint = bound[iMarker][iElem]->GetNode(iNode); /*--- Set the vertex in the node information ---*/ - + if ((node[iPoint]->GetVertex(iMarker) == -1) || (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE)) { iVertex = nVertex[iMarker]; vertex[iMarker][iVertex] = new CVertex(iPoint, nDim); - + if (config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) { vertex[iMarker][iVertex]->SetRotation_Type(bound[iMarker][iElem]->GetRotation_Type()); } @@ -9457,7 +5755,7 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, su2double *coord, *valueSpan, min, max, radius, delta; short PeriodicBoundary; unsigned short SpanWise_Kind = config->GetKind_SpanWise(); - + #ifdef HAVE_MPI unsigned short iSize; int nSpan_max; @@ -9510,14 +5808,12 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, /*--- if parallel computing the global number of span---*/ #ifdef HAVE_MPI nSpan_max = nSpan; - My_nSpan = nSpan; nSpan = 0; - My_MaxnSpan = nSpan_max; nSpan_max = 0; + My_nSpan = nSpan; nSpan = 0; + My_MaxnSpan = nSpan_max; nSpan_max = 0; SU2_MPI::Allreduce(&My_nSpan, &nSpan, 1, MPI_INT, MPI_SUM, MPI_COMM_WORLD); SU2_MPI::Allreduce(&My_MaxnSpan, &nSpan_max, 1, MPI_INT, MPI_MAX, MPI_COMM_WORLD); #endif - - /*--- initialize the vector that will contain the disordered values span-wise ---*/ nSpanWiseSections[marker_flag -1] = nSpan; valueSpan = new su2double[nSpan]; @@ -9582,9 +5878,9 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, /*--- Gather the span-wise values on all the processor ---*/ #ifdef HAVE_MPI - MyTotValueSpan = new su2double[nSpan_max*size]; - MyValueSpan = new su2double[nSpan_max]; - My_nSpan_loc = new int[size]; + MyTotValueSpan = new su2double[nSpan_max*size]; + MyValueSpan = new su2double[nSpan_max]; + My_nSpan_loc = new int[size]; for(iSpan = 0; iSpan < nSpan_max; iSpan++){ MyValueSpan[iSpan] = -1001.0; for (iSize = 0; iSize< size; iSize++){ @@ -9718,14 +6014,14 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, } /*--- compute global minimum and maximum value on span-wise ---*/ #ifdef HAVE_MPI - MyMin= min; min = 0; - MyMax= max; max = 0; + MyMin= min; min = 0; + MyMax= max; max = 0; SU2_MPI::Allreduce(&MyMin, &min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); SU2_MPI::Allreduce(&MyMax, &max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); #endif - // cout <<"min " << min << endl; - // cout <<"max " << max << endl; + // cout <<"min " << min << endl; + // cout <<"max " << max << endl; /*--- compute height value for each spanwise section---*/ delta = (max - min)/(nSpanWiseSections[marker_flag-1] -1); for(iSpan = 0; iSpan < nSpanWiseSections[marker_flag-1]; iSpan++){ @@ -9745,8 +6041,6 @@ void CPhysicalGeometry::ComputeNSpan(CConfig *config, unsigned short val_iZone, } } - - } } @@ -9759,7 +6053,7 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone min = 10.0E+06; minInt = 10.0E+06; max = -10.0E+06; - + su2double radius; long iVertex, iSpanVertex, jSpanVertex, kSpanVertex = 0; int *nTotVertex_gb, *nVertexSpanHalo; @@ -10398,7 +6692,9 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone min = 10.0E+06; for(jSize= 0; jSize < size; jSize++){ for(jSpanVertex = 0; jSpanVertex < nTotVertex_gb[iSpan]; jSpanVertex++){ - if (angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex] < min && (angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex] - target) >= 0.0 && !checkAssign_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex]){ + if ((angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex] < min) && + (angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex] >= target) && + !checkAssign_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex]) { kSize = jSize; kSpanVertex = jSpanVertex; min = angCoord_gb[jSize*nTotVertex_gb[iSpan] + jSpanVertex]; @@ -10407,7 +6703,6 @@ void CPhysicalGeometry::SetTurboVertex(CConfig *config, unsigned short val_iZone } } - delete [] x_gb; delete [] y_gb; delete [] z_gb; delete [] angCoord_gb; delete [] deltaAngCoord_gb; delete[] checkAssign_gb; } @@ -11069,40 +7364,40 @@ void CPhysicalGeometry::SetCoord_CG(void) { unsigned short nNode, iDim, iMarker, iNode; unsigned long elem_poin, edge_poin, iElem, iEdge; su2double **Coord; - + /*--- Compute the center of gravity for elements ---*/ - + for (iElem = 0; iElemGetnNodes(); Coord = new su2double* [nNode]; - + /*--- Store the coordinates for all the element nodes ---*/ - + for (iNode = 0; iNode < nNode; iNode++) { elem_poin = elem[iElem]->GetNode(iNode); Coord[iNode] = new su2double [nDim]; for (iDim = 0; iDim < nDim; iDim++) Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim); } - + /*--- Compute the element CG coordinates ---*/ - + elem[iElem]->SetCoord_CG(Coord); - + for (iNode = 0; iNode < nNode; iNode++) if (Coord[iNode] != NULL) delete[] Coord[iNode]; if (Coord != NULL) delete[] Coord; } - + /*--- Center of gravity for face elements ---*/ - + for (iMarker = 0; iMarker < nMarker; iMarker++) for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { nNode = bound[iMarker][iElem]->GetnNodes(); Coord = new su2double* [nNode]; - + /*--- Store the coordinates for all the element nodes ---*/ - + for (iNode = 0; iNode < nNode; iNode++) { elem_poin = bound[iMarker][iElem]->GetNode(iNode); Coord[iNode] = new su2double [nDim]; @@ -11110,32 +7405,32 @@ void CPhysicalGeometry::SetCoord_CG(void) { Coord[iNode][iDim]=node[elem_poin]->GetCoord(iDim); } /*--- Compute the element CG coordinates ---*/ - + bound[iMarker][iElem]->SetCoord_CG(Coord); for (iNode = 0; iNode < nNode; iNode++) if (Coord[iNode] != NULL) delete[] Coord[iNode]; if (Coord != NULL) delete[] Coord; } - + /*--- Center of gravity for edges ---*/ - + for (iEdge = 0; iEdge < nEdge; iEdge++) { nNode = edge[iEdge]->GetnNodes(); Coord = new su2double* [nNode]; - + /*--- Store the coordinates for all the element nodes ---*/ - + for (iNode = 0; iNode < nNode; iNode++) { edge_poin=edge[iEdge]->GetNode(iNode); Coord[iNode] = new su2double [nDim]; for (iDim = 0; iDim < nDim; iDim++) Coord[iNode][iDim]=node[edge_poin]->GetCoord(iDim); } - + /*--- Compute the edge CG coordinates ---*/ - + edge[iEdge]->SetCoord_CG(Coord); - + for (iNode = 0; iNode < nNode; iNode++) if (Coord[iNode] != NULL) delete[] Coord[iNode]; if (Coord != NULL) delete[] Coord; @@ -11147,40 +7442,40 @@ void CPhysicalGeometry::SetBoundControlVolume(CConfig *config, unsigned short ac unsigned long Neighbor_Point, iVertex, iPoint, iElem; long iEdge; su2double Area, *NormalFace = NULL; - + /*--- Update values of faces of the edge ---*/ - + if (action != ALLOCATE) for (iMarker = 0; iMarker < nMarker; iMarker++) for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) vertex[iMarker][iVertex]->SetZeroValues(); - + su2double *Coord_Edge_CG = new su2double [nDim]; su2double *Coord_Elem_CG = new su2double [nDim]; su2double *Coord_Vertex = new su2double [nDim]; - + /*--- Loop over all the markers ---*/ - + for (iMarker = 0; iMarker < nMarker; iMarker++) - + /*--- Loop over all the boundary elements ---*/ - + for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) - + /*--- Loop over all the nodes of the boundary ---*/ - + for (iNode = 0; iNode < bound[iMarker][iElem]->GetnNodes(); iNode++) { iPoint = bound[iMarker][iElem]->GetNode(iNode); iVertex = node[iPoint]->GetVertex(iMarker); - + /*--- Loop over the neighbor nodes, there is a face for each one ---*/ - + for (iNeighbor_Nodes = 0; iNeighbor_Nodes < bound[iMarker][iElem]->GetnNeighbor_Nodes(iNode); iNeighbor_Nodes++) { Neighbor_Node = bound[iMarker][iElem]->GetNeighbor_Nodes(iNode, iNeighbor_Nodes); Neighbor_Point = bound[iMarker][iElem]->GetNode(Neighbor_Node); - + /*--- Shared edge by the Neighbor Point and the point ---*/ - + iEdge = FindEdge(iPoint, Neighbor_Point); for (iDim = 0; iDim < nDim; iDim++) { Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); @@ -11189,29 +7484,29 @@ void CPhysicalGeometry::SetBoundControlVolume(CConfig *config, unsigned short ac } switch (nDim) { case 2: - + /*--- Store the 2D face ---*/ - + if (iNode == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Vertex); if (iNode == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Vertex, Coord_Elem_CG); break; case 3: - + /*--- Store the 3D face ---*/ - + if (iNeighbor_Nodes == 0) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Elem_CG, Coord_Edge_CG, Coord_Vertex); if (iNeighbor_Nodes == 1) vertex[iMarker][iVertex]->SetNodes_Coord(Coord_Edge_CG, Coord_Elem_CG, Coord_Vertex); break; } } } - + delete[] Coord_Edge_CG; delete[] Coord_Elem_CG; delete[] Coord_Vertex; - + /*--- Check if there is a normal with null area ---*/ - + for (iMarker = 0; iMarker < nMarker; iMarker ++) for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { NormalFace = vertex[iMarker][iVertex]->GetNormal(); @@ -11219,7 +7514,7 @@ void CPhysicalGeometry::SetBoundControlVolume(CConfig *config, unsigned short ac Area = sqrt(Area); if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; } - + } void CPhysicalGeometry::SetMaxLength(CConfig* config) { @@ -11278,28 +7573,28 @@ void CPhysicalGeometry::SetMaxLength(CConfig* config) { } void CPhysicalGeometry::MatchNearField(CConfig *config) { - + su2double epsilon = 1e-1; - + unsigned short nMarker_NearFieldBound = config->GetnMarker_NearFieldBound(); - + if (nMarker_NearFieldBound != 0) { - + unsigned short iMarker, iDim, jMarker, pMarker = 0; unsigned long iVertex, iPoint, pVertex = 0, pPoint = 0, jVertex, jPoint, iPointGlobal, jPointGlobal, jVertex_, pPointGlobal = 0; su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local, maxdist_global; int iProcessor, pProcessor = 0; unsigned long nLocalVertex_NearField = 0, MaxLocalVertex_NearField = 0; int nProcessor = size; - + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - + if (rank == MASTER_NODE) cout << "Set NearField boundary conditions (if any)." << endl; - + /*--- Compute the number of vertex that have interfase boundary condition without including the ghost nodes ---*/ - + nLocalVertex_NearField = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) @@ -11307,37 +7602,32 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { iPoint = vertex[iMarker][iVertex]->GetNode(); if (node[iPoint]->GetDomain()) nLocalVertex_NearField ++; } - + Buffer_Send_nVertex[0] = nLocalVertex_NearField; - + /*--- Send NearField vertex information --*/ - -#ifndef HAVE_MPI - MaxLocalVertex_NearField = nLocalVertex_NearField; - Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0]; -#else + SU2_MPI::Allreduce(&nLocalVertex_NearField, &MaxLocalVertex_NearField, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_NearField*nDim]; unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_NearField]; unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_NearField]; unsigned long *Buffer_Send_Vertex = new unsigned long [MaxLocalVertex_NearField]; unsigned long *Buffer_Send_Marker = new unsigned long [MaxLocalVertex_NearField]; - + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_NearField*nDim]; unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_NearField]; unsigned long *Buffer_Receive_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_NearField]; unsigned long *Buffer_Receive_Vertex = new unsigned long [nProcessor*MaxLocalVertex_NearField]; unsigned long *Buffer_Receive_Marker = new unsigned long [nProcessor*MaxLocalVertex_NearField]; - + unsigned long nBuffer_Coord = MaxLocalVertex_NearField*nDim; unsigned long nBuffer_Point = MaxLocalVertex_NearField; unsigned long nBuffer_GlobalIndex = MaxLocalVertex_NearField; unsigned long nBuffer_Vertex = MaxLocalVertex_NearField; unsigned long nBuffer_Marker = MaxLocalVertex_NearField; - + for (iVertex = 0; iVertex < MaxLocalVertex_NearField; iVertex++) { Buffer_Send_Point[iVertex] = 0; Buffer_Send_GlobalIndex[iVertex] = 0; @@ -11346,9 +7636,9 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { for (iDim = 0; iDim < nDim; iDim++) Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; } - + /*--- Copy coordinates and point to the auxiliar vector --*/ - + nLocalVertex_NearField = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) @@ -11365,43 +7655,30 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { nLocalVertex_NearField++; } } - -#ifndef HAVE_MPI - for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++) - Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord]; - for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++) - Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point]; - for (unsigned long iBuffer_GlobalIndex = 0; iBuffer_GlobalIndex < nBuffer_GlobalIndex; iBuffer_GlobalIndex++) - Buffer_Receive_GlobalIndex[iBuffer_GlobalIndex] = Buffer_Send_GlobalIndex[iBuffer_GlobalIndex]; - for (unsigned long iBuffer_Vertex = 0; iBuffer_Vertex < nBuffer_Vertex; iBuffer_Vertex++) - Buffer_Receive_Vertex[iBuffer_Vertex] = Buffer_Send_Vertex[iBuffer_Vertex]; - for (unsigned long iBuffer_Marker = 0; iBuffer_Marker < nBuffer_Marker; iBuffer_Marker++) - Buffer_Receive_Marker[iBuffer_Marker] = Buffer_Send_Marker[iBuffer_Marker]; -#else + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, Buffer_Receive_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, Buffer_Receive_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - - + + /*--- Compute the closest point to a Near-Field boundary point ---*/ - + maxdist_local = 0.0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { iPoint = vertex[iMarker][iVertex]->GetNode(); iPointGlobal = node[iPoint]->GetGlobalIndex(); - + if (node[iPoint]->GetDomain()) { - + /*--- Coordinates of the boundary point ---*/ - + Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; - + /*--- Loop over all the boundaries to find the pair ---*/ for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { @@ -11409,16 +7686,16 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { jPointGlobal = Buffer_Receive_GlobalIndex[iProcessor*MaxLocalVertex_NearField+jVertex]; jVertex_ = Buffer_Receive_Vertex[iProcessor*MaxLocalVertex_NearField+jVertex]; jMarker = Buffer_Receive_Marker[iProcessor*MaxLocalVertex_NearField+jVertex]; - + if (jPointGlobal != iPointGlobal) { - + /*--- Compute the distance ---*/ - + dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_NearField+jVertex)*nDim+iDim]; dist += pow(Coord_j[iDim]-Coord_i[iDim],2.0); } dist = sqrt(dist); - + if (((dist < mindist) && (iProcessor != rank)) || ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { mindist = dist; pProcessor = iProcessor; pPoint = jPoint; pPointGlobal = jPointGlobal; @@ -11427,12 +7704,12 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { } } } - + /*--- Store the value of the pair ---*/ - + maxdist_local = max(maxdist_local, mindist); vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pPointGlobal, pVertex, pMarker, pProcessor); - + if (mindist > epsilon) { cout.precision(10); cout << endl; @@ -11441,26 +7718,22 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iPointGlobal, pVertex, pMarker, pProcessor); maxdist_local = min(maxdist_local, 0.0); } - + } } } } - -#ifndef HAVE_MPI - maxdist_global = maxdist_local; -#else + SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); -#endif - + if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; - + delete[] Buffer_Send_Coord; delete[] Buffer_Send_Point; - + delete[] Buffer_Receive_Coord; delete[] Buffer_Receive_Point; - + delete[] Buffer_Send_nVertex; delete[] Buffer_Receive_nVertex; @@ -11471,19 +7744,19 @@ void CPhysicalGeometry::MatchNearField(CConfig *config) { delete [] Buffer_Receive_GlobalIndex; delete [] Buffer_Receive_Vertex; delete [] Buffer_Receive_Marker; - + } - + } void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { - + su2double epsilon = 1e-1; - + unsigned short nMarker_ActDiskInlet = config->GetnMarker_ActDiskInlet(); - + if (nMarker_ActDiskInlet != 0) { - + unsigned short iMarker, iDim; unsigned long iVertex, iPoint, iPointGlobal, pPoint = 0, pPointGlobal = 0, pVertex = 0, pMarker = 0, jVertex, jVertex_, jPoint, jPointGlobal, jMarker; su2double *Coord_i, Coord_j[3], dist = 0.0, mindist, maxdist_local = 0.0, maxdist_global = 0.0; @@ -11492,21 +7765,21 @@ void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { int nProcessor = size; unsigned short Beneficiary = 0, Donor = 0, iBC; bool Perimeter; - + for (iBC = 0; iBC < 2; iBC++) { - + if (iBC == 0) { Beneficiary = ACTDISK_INLET; Donor = ACTDISK_OUTLET; } if (iBC == 1) { Beneficiary = ACTDISK_OUTLET; Donor = ACTDISK_INLET; } - + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; unsigned long *Buffer_Receive_nVertex = new unsigned long [nProcessor]; - + if ((iBC == 0) && (rank == MASTER_NODE)) cout << "Set Actuator Disk inlet boundary conditions." << endl; if ((iBC == 1) && (rank == MASTER_NODE)) cout << "Set Actuator Disk outlet boundary conditions." << endl; - + /*--- Compute the number of vertex that have an actuator disk outlet boundary condition without including the ghost nodes ---*/ - + nLocalVertex_ActDisk = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == Donor) { @@ -11516,39 +7789,34 @@ void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { } } } - + Buffer_Send_nVertex[0] = nLocalVertex_ActDisk; - + /*--- Send actuator disk vertex information --*/ - -#ifndef HAVE_MPI - MaxLocalVertex_ActDisk = nLocalVertex_ActDisk; - Buffer_Receive_nVertex[0] = Buffer_Send_nVertex[0]; -#else + SU2_MPI::Allreduce(&nLocalVertex_ActDisk, &MaxLocalVertex_ActDisk, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Receive_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - + /*--- Array dimensionalization --*/ - + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_ActDisk*nDim]; unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_ActDisk]; unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_ActDisk]; unsigned long *Buffer_Send_Vertex = new unsigned long [MaxLocalVertex_ActDisk]; unsigned long *Buffer_Send_Marker = new unsigned long [MaxLocalVertex_ActDisk]; - + su2double *Buffer_Receive_Coord = new su2double [nProcessor*MaxLocalVertex_ActDisk*nDim]; unsigned long *Buffer_Receive_Point = new unsigned long [nProcessor*MaxLocalVertex_ActDisk]; unsigned long *Buffer_Receive_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_ActDisk]; unsigned long *Buffer_Receive_Vertex = new unsigned long [nProcessor*MaxLocalVertex_ActDisk]; unsigned long *Buffer_Receive_Marker = new unsigned long [nProcessor*MaxLocalVertex_ActDisk]; - + unsigned long nBuffer_Coord = MaxLocalVertex_ActDisk*nDim; unsigned long nBuffer_Point = MaxLocalVertex_ActDisk; unsigned long nBuffer_GlobalIndex = MaxLocalVertex_ActDisk; unsigned long nBuffer_Vertex = MaxLocalVertex_ActDisk; unsigned long nBuffer_Marker = MaxLocalVertex_ActDisk; - + for (iVertex = 0; iVertex < MaxLocalVertex_ActDisk; iVertex++) { Buffer_Send_Point[iVertex] = 0; Buffer_Send_GlobalIndex[iVertex] = 0; @@ -11557,9 +7825,9 @@ void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { for (iDim = 0; iDim < nDim; iDim++) Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; } - + /*--- Copy coordinates and point to the auxiliar vector --*/ - + nLocalVertex_ActDisk = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == Donor) { @@ -11578,85 +7846,71 @@ void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { } } } - -#ifndef HAVE_MPI - for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++) - Buffer_Receive_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord]; - for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++) - Buffer_Receive_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point]; - for (unsigned long iBuffer_GlobalIndex = 0; iBuffer_GlobalIndex < nBuffer_GlobalIndex; iBuffer_GlobalIndex++) - Buffer_Receive_GlobalIndex[iBuffer_GlobalIndex] = Buffer_Send_GlobalIndex[iBuffer_GlobalIndex]; - for (unsigned long iBuffer_Vertex = 0; iBuffer_Vertex < nBuffer_Vertex; iBuffer_Vertex++) - Buffer_Receive_Vertex[iBuffer_Vertex] = Buffer_Send_Vertex[iBuffer_Vertex]; - for (unsigned long iBuffer_Marker = 0; iBuffer_Marker < nBuffer_Marker; iBuffer_Marker++) - Buffer_Receive_Marker[iBuffer_Marker] = Buffer_Send_Marker[iBuffer_Marker]; - -#else + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Receive_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, Buffer_Receive_Point, nBuffer_Point, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, Buffer_Receive_GlobalIndex, nBuffer_GlobalIndex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, Buffer_Receive_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, Buffer_Receive_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - + /*--- Compute the closest point to an actuator disk inlet point ---*/ - + maxdist_local = 0.0; - + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == Beneficiary) { - + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { iPoint = vertex[iMarker][iVertex]->GetNode(); iPointGlobal = node[iPoint]->GetGlobalIndex(); - - + + if (node[iPoint]->GetDomain()) { - + /*--- Coordinates of the boundary point ---*/ - + Coord_i = node[iPoint]->GetCoord(); mindist = 1E6; pProcessor = 0; pPoint = 0; - + /*--- Loop over all the boundaries to find the pair ---*/ - + Perimeter = false; - + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) { for (jVertex = 0; jVertex < Buffer_Receive_nVertex[iProcessor]; jVertex++) { jPoint = Buffer_Receive_Point[iProcessor*MaxLocalVertex_ActDisk+jVertex]; jPointGlobal = Buffer_Receive_GlobalIndex[iProcessor*MaxLocalVertex_ActDisk+jVertex]; jVertex_ = Buffer_Receive_Vertex[iProcessor*MaxLocalVertex_ActDisk+jVertex]; jMarker = Buffer_Receive_Marker[iProcessor*MaxLocalVertex_ActDisk+jVertex]; - + // if (jPointGlobal != iPointGlobal) { // ActDisk_Perimeter /*--- Compute the distance ---*/ - + dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { Coord_j[iDim] = Buffer_Receive_Coord[(iProcessor*MaxLocalVertex_ActDisk+jVertex)*nDim+iDim]; dist += pow(Coord_j[iDim]-Coord_i[iDim], 2.0); } dist = sqrt(dist); - + if (dist < mindist) { mindist = dist; pProcessor = iProcessor; pPoint = jPoint; pPointGlobal = jPointGlobal; pVertex = jVertex_; pMarker = jMarker; if (dist == 0.0) break; } - + // } // else { Perimeter = true; mindist = 0.0; dist = 0.0; break; } } } - + /*--- Store the value of the pair ---*/ - + maxdist_local = max(maxdist_local, mindist); vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pPointGlobal, pVertex, pMarker, pProcessor); vertex[iMarker][iVertex]->SetActDisk_Perimeter(Perimeter); - + if (mindist > epsilon) { cout.precision(10); cout << endl; @@ -11665,27 +7919,23 @@ void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { vertex[iMarker][iVertex]->SetDonorPoint(iPoint, iPointGlobal, pVertex, pMarker, pProcessor); maxdist_local = min(maxdist_local, 0.0); } - + } } - + } } - -#ifndef HAVE_MPI - maxdist_global = maxdist_local; -#else + SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); -#endif - + if (rank == MASTER_NODE) cout <<"The max distance between points is: " << maxdist_global <<"."<< endl; - + delete[] Buffer_Send_Coord; delete[] Buffer_Send_Point; - + delete[] Buffer_Receive_Coord; delete[] Buffer_Receive_Point; - + delete[] Buffer_Send_nVertex; delete[] Buffer_Receive_nVertex; @@ -11696,15 +7946,15 @@ void CPhysicalGeometry::MatchActuator_Disk(CConfig *config) { delete [] Buffer_Receive_GlobalIndex; delete [] Buffer_Receive_Vertex; delete [] Buffer_Receive_Marker; - + } } - + } void CPhysicalGeometry::MatchPeriodic(CConfig *config, unsigned short val_periodic) { - + unsigned short iMarker, iDim, jMarker, pMarker = 0; unsigned short iPeriodic, nPeriodic; @@ -11717,33 +7967,33 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, int iProcessor, pProcessor = 0, nProcessor = size; bool isBadMatch = false; - + string Marker_Tag; - + su2double *Coord_i, Coord_j[3], dist, mindist, maxdist_local, maxdist_global; su2double *center, *angles, translation[3]={0.0,0.0,0.0}, *trans, dx, dy, dz; su2double rotMatrix[3][3] = {{1.0,0.0,0.0},{0.0,1.0,0.0},{0.0,0.0,1.0}}; su2double Theta, Phi, Psi, cosTheta, sinTheta, cosPhi, sinPhi, cosPsi, sinPsi; su2double rotCoord[3] = {0.0, 0.0, 0.0}; - + /*--- Tolerance for distance-based match to report warning. ---*/ - + su2double epsilon = 1e-6; - + /*--- Evaluate the number of periodic boundary conditions ---*/ - + nPeriodic = config->GetnMarker_Periodic(); - + /*--- Send an initial message to the console. ---*/ - + if (rank == MASTER_NODE) { cout << "Matching the periodic boundary points for marker pair "; cout << val_periodic << "." << endl; } - + /*--- Compute the total number of vertices that sit on a periodic boundary on our local rank. We only include our "owned" nodes. ---*/ - + nLocalVertex_Periodic = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { @@ -11757,48 +8007,43 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, } } } - + /*--- Communicate our local periodic point count globally and receive the counts of periodic points from all other ranks.---*/ - + unsigned long *Buffer_Send_nVertex = new unsigned long [1]; unsigned long *Buffer_Recv_nVertex = new unsigned long [nProcessor]; - + Buffer_Send_nVertex[0] = nLocalVertex_Periodic; - + /*--- Copy our own count in serial or use collective comms with MPI. ---*/ - -#ifndef HAVE_MPI - MaxLocalVertex_Periodic = nLocalVertex_Periodic; - Buffer_Recv_nVertex[0] = Buffer_Send_nVertex[0]; -#else + SU2_MPI::Allreduce(&nLocalVertex_Periodic, &MaxLocalVertex_Periodic, 1, MPI_UNSIGNED_LONG, MPI_MAX, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_nVertex, 1, MPI_UNSIGNED_LONG, Buffer_Recv_nVertex, 1, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - + /*--- Prepare buffers to send the information for each periodic point to all ranks so that we can match pairs. ---*/ - + su2double *Buffer_Send_Coord = new su2double [MaxLocalVertex_Periodic*nDim]; unsigned long *Buffer_Send_Point = new unsigned long [MaxLocalVertex_Periodic]; unsigned long *Buffer_Send_GlobalIndex = new unsigned long [MaxLocalVertex_Periodic]; unsigned long *Buffer_Send_Vertex = new unsigned long [MaxLocalVertex_Periodic]; unsigned long *Buffer_Send_Marker = new unsigned long [MaxLocalVertex_Periodic]; - + su2double *Buffer_Recv_Coord = new su2double [nProcessor*MaxLocalVertex_Periodic*nDim]; unsigned long *Buffer_Recv_Point = new unsigned long [nProcessor*MaxLocalVertex_Periodic]; unsigned long *Buffer_Recv_GlobalIndex = new unsigned long [nProcessor*MaxLocalVertex_Periodic]; unsigned long *Buffer_Recv_Vertex = new unsigned long [nProcessor*MaxLocalVertex_Periodic]; unsigned long *Buffer_Recv_Marker = new unsigned long [nProcessor*MaxLocalVertex_Periodic]; - + unsigned long nBuffer_Coord = MaxLocalVertex_Periodic*nDim; unsigned long nBuffer_Point = MaxLocalVertex_Periodic; unsigned long nBuffer_GlobalIndex = MaxLocalVertex_Periodic; unsigned long nBuffer_Vertex = MaxLocalVertex_Periodic; unsigned long nBuffer_Marker = MaxLocalVertex_Periodic; - + for (iVertex = 0; iVertex < MaxLocalVertex_Periodic; iVertex++) { Buffer_Send_Point[iVertex] = 0; Buffer_Send_GlobalIndex[iVertex] = 0; @@ -11807,12 +8052,12 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, for (iDim = 0; iDim < nDim; iDim++) Buffer_Send_Coord[iVertex*nDim+iDim] = 0.0; } - + /*--- Store the local index, global index, local boundary index, marker index, and point coordinates in the buffers for sending. Note again that this is only for the current pair of periodic markers and for only the "owned" points on each rank. ---*/ - + nLocalVertex_Periodic = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { @@ -11835,25 +8080,13 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, } } } - + /*--- Copy our own data in serial or use collective comms to gather the data for all points on each rank with MPI. Note that, since the periodic point count should be small relative to the volume grid and we are only storing one periodic marker pair at a time, repeating the data for each pair on all ranks should be manageable. ---*/ - -#ifndef HAVE_MPI - for (unsigned long iBuffer_Coord = 0; iBuffer_Coord < nBuffer_Coord; iBuffer_Coord++) - Buffer_Recv_Coord[iBuffer_Coord] = Buffer_Send_Coord[iBuffer_Coord]; - for (unsigned long iBuffer_Point = 0; iBuffer_Point < nBuffer_Point; iBuffer_Point++) - Buffer_Recv_Point[iBuffer_Point] = Buffer_Send_Point[iBuffer_Point]; - for (unsigned long iBuffer_GlobalIndex = 0; iBuffer_GlobalIndex < nBuffer_GlobalIndex; iBuffer_GlobalIndex++) - Buffer_Recv_GlobalIndex[iBuffer_GlobalIndex] = Buffer_Send_GlobalIndex[iBuffer_GlobalIndex]; - for (unsigned long iBuffer_Vertex = 0; iBuffer_Vertex < nBuffer_Vertex; iBuffer_Vertex++) - Buffer_Recv_Vertex[iBuffer_Vertex] = Buffer_Send_Vertex[iBuffer_Vertex]; - for (unsigned long iBuffer_Marker = 0; iBuffer_Marker < nBuffer_Marker; iBuffer_Marker++) - Buffer_Recv_Marker[iBuffer_Marker] = Buffer_Send_Marker[iBuffer_Marker]; -#else + SU2_MPI::Allgather(Buffer_Send_Coord, nBuffer_Coord, MPI_DOUBLE, Buffer_Recv_Coord, nBuffer_Coord, MPI_DOUBLE, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Point, nBuffer_Point, MPI_UNSIGNED_LONG, @@ -11864,165 +8097,164 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, Buffer_Recv_Vertex, nBuffer_Vertex, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); SU2_MPI::Allgather(Buffer_Send_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, Buffer_Recv_Marker, nBuffer_Marker, MPI_UNSIGNED_LONG, MPI_COMM_WORLD); -#endif - + /*--- Now that all ranks have the data for all periodic points for this pair of periodic markers, we match the individual points based on the translation / rotation specified for the marker pair. ---*/ - + maxdist_local = 0.0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - + iPeriodic = config->GetMarker_All_PerBound(iMarker); if ((iPeriodic == val_periodic) || (iPeriodic == val_periodic + nPeriodic/2)) { - + /*--- Retrieve the supplied periodic information. ---*/ - + Marker_Tag = config->GetMarker_All_TagBound(iMarker); center = config->GetPeriodicRotCenter(Marker_Tag); angles = config->GetPeriodicRotAngles(Marker_Tag); trans = config->GetPeriodicTranslation(Marker_Tag); /*--- Store (center+trans) as it is constant and will be added. ---*/ - + translation[0] = center[0] + trans[0]; translation[1] = center[1] + trans[1]; translation[2] = center[2] + trans[2]; - + /*--- Store angles separately for clarity. Compute sines/cosines. ---*/ - + Theta = angles[0]; Phi = angles[1]; Psi = angles[2]; cosTheta = cos(Theta); cosPhi = cos(Phi); cosPsi = cos(Psi); sinTheta = sin(Theta); sinPhi = sin(Phi); sinPsi = sin(Psi); - + /*--- Compute the rotation matrix. Note that the implicit ordering is rotation about the x-axis, y-axis, then z-axis. ---*/ - + rotMatrix[0][0] = cosPhi*cosPsi; rotMatrix[1][0] = cosPhi*sinPsi; rotMatrix[2][0] = -sinPhi; - + rotMatrix[0][1] = sinTheta*sinPhi*cosPsi - cosTheta*sinPsi; rotMatrix[1][1] = sinTheta*sinPhi*sinPsi + cosTheta*cosPsi; rotMatrix[2][1] = sinTheta*cosPhi; - + rotMatrix[0][2] = cosTheta*sinPhi*cosPsi + sinTheta*sinPsi; rotMatrix[1][2] = cosTheta*sinPhi*sinPsi - sinTheta*cosPsi; rotMatrix[2][2] = cosTheta*cosPhi; - + /*--- Loop over each point on the periodic marker that this rank holds locally and find the matching point from the donor marker. ---*/ - + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - + /*--- Local and global index for the owned periodic point. ---*/ - + iPoint = vertex[iMarker][iVertex]->GetNode(); iPointGlobal = node[iPoint]->GetGlobalIndex(); - + /*--- If this is not a ghost, find the periodic match. ---*/ - + if (node[iPoint]->GetDomain()) { - + /*--- Coordinates of the current boundary point ---*/ - + Coord_i = node[iPoint]->GetCoord(); - + /*--- Get the position vector from rotation center to point. ---*/ - + dx = Coord_i[0] - center[0]; dy = Coord_i[1] - center[1]; if (nDim == 3) dz = Coord_i[2] - center[2]; else dz = 0.0; - + /*--- Compute transformed point coordinates. ---*/ - + rotCoord[0] = (rotMatrix[0][0]*dx + rotMatrix[0][1]*dy + rotMatrix[0][2]*dz + translation[0]); - + rotCoord[1] = (rotMatrix[1][0]*dx + rotMatrix[1][1]*dy + rotMatrix[1][2]*dz + translation[1]); - + rotCoord[2] = (rotMatrix[2][0]*dx + rotMatrix[2][1]*dy + rotMatrix[2][2]*dz + translation[2]); - + /*--- Our search is based on the minimum distance, so we initialize the distance to a large value. ---*/ - + mindist = 1E6; pProcessor = 0; pPoint = 0; - + /*--- Loop over all of the periodic data that was gathered from all ranks in order to find the matching periodic point. ---*/ - + for (iProcessor = 0; iProcessor < nProcessor; iProcessor++) for (jVertex = 0; jVertex < Buffer_Recv_nVertex[iProcessor]; jVertex++) { - + /*--- Store the loop index more easily. ---*/ - + index = iProcessor*MaxLocalVertex_Periodic + jVertex; - + /*--- For each candidate, we have the local and global index, along with the boundary vertex and marker index. ---*/ - + jPoint = Buffer_Recv_Point[index]; jPointGlobal = Buffer_Recv_GlobalIndex[index]; jVertex_ = Buffer_Recv_Vertex[index]; jMarker = Buffer_Recv_Marker[index]; - + /*--- The gathered data will also include the current "owned" periodic point that we are matching, so first make sure that we avoid the original point by checking that the global index values are not the same. ---*/ - + if ((jPointGlobal != iPointGlobal)) { - + /*--- Compute the distance between the candidate periodic point and the transformed coordinates of the owned point. ---*/ - + dist = 0.0; for (iDim = 0; iDim < nDim; iDim++) { Coord_j[iDim] = Buffer_Recv_Coord[index*nDim + iDim]; dist += pow(Coord_j[iDim]-rotCoord[iDim],2.0); } dist = sqrt(dist); - + /*--- Compare the distance against the existing minimum and also perform checks just to be sure that this is an independent periodic point (even if on the same rank). ---*/ - + if (((dist < mindist) && (iProcessor != rank)) || ((dist < mindist) && (iProcessor == rank) && (jPoint != iPoint))) { - + /*--- We have found an intermediate match. Store the data for this point before continuing the search. ---*/ - + mindist = dist; pProcessor = iProcessor; pPoint = jPoint; pPointGlobal = jPointGlobal; pVertex = jVertex_; pMarker = jMarker; - + } } - + } - + /*--- Store the data for the best match found for the owned periodic point. ---*/ - + vertex[iMarker][iVertex]->SetDonorPoint(pPoint, pPointGlobal, pVertex, pMarker, pProcessor); maxdist_local = max(maxdist_local, mindist); nPointMatch++; - + /*--- If the distance to the closest point is larger than our tolerance, then throw a warning for this point. ---*/ - + if (mindist > epsilon) { cout.precision(10); cout << endl; @@ -12031,29 +8263,25 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, maxdist_local = min(maxdist_local, 0.0); isBadMatch = true; } - + } } } } } - + /*--- Communicate the final count of number of matched points for the periodic boundary pair and the max distance for all pairs of points. ---*/ - -#ifndef HAVE_MPI - maxdist_global = maxdist_local; -#else + unsigned long nPointMatch_Local = nPointMatch; SU2_MPI::Reduce(&nPointMatch_Local, &nPointMatch, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, MPI_COMM_WORLD); SU2_MPI::Reduce(&maxdist_local, &maxdist_global, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, MPI_COMM_WORLD); -#endif - + /*--- Output some information about the matching process. ---*/ - + if (rank == MASTER_NODE) { if (nPointMatch > 0) { cout <<" Matched " << nPointMatch << " points with a max distance of: "; @@ -12062,35 +8290,35 @@ void CPhysicalGeometry::MatchPeriodic(CConfig *config, cout <<" No matching points for periodic marker pair "; cout << val_periodic << " in current zone." << endl; } - + /*--- Print final warning when finding bad matches. ---*/ - + if (isBadMatch) { cout << endl; cout << "\n !!! Warning !!!" << endl; cout << "Bad matches found. Computation will continue, but be cautious.\n"; } } - + /*--- Free local memory for communications. ---*/ - + delete[] Buffer_Send_Coord; delete[] Buffer_Send_Point; - + delete[] Buffer_Recv_Coord; delete[] Buffer_Recv_Point; - + delete[] Buffer_Send_nVertex; delete[] Buffer_Recv_nVertex; - + delete [] Buffer_Send_GlobalIndex; delete [] Buffer_Send_Vertex; delete [] Buffer_Send_Marker; - + delete [] Buffer_Recv_GlobalIndex; delete [] Buffer_Recv_Vertex; delete [] Buffer_Recv_Marker; - + } void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) { @@ -12108,31 +8336,31 @@ void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) for (iPoint = 0; iPoint < nPoint; iPoint++) node[iPoint]->SetVolume (0.0); } - + Coord_Edge_CG = new su2double [nDim]; Coord_FaceElem_CG = new su2double [nDim]; Coord_Elem_CG = new su2double [nDim]; Coord_FaceiPoint = new su2double [nDim]; Coord_FacejPoint = new su2double [nDim]; - + my_DomainVolume = 0.0; for (iElem = 0; iElem < nElem; iElem++) for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { - + /*--- In 2D all the faces have only one edge ---*/ if (nDim == 2) nEdgesFace = 1; /*--- In 3D the number of edges per face is the same as the number of point per face ---*/ if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); - + /*-- Loop over the edges of a face ---*/ for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { - + /*--- In 2D only one edge (two points) per edge ---*/ if (nDim == 2) { face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); } - + /*--- In 3D there are several edges in each face ---*/ if (nDim == 3) { face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); @@ -12141,12 +8369,12 @@ void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) else face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); } - + /*--- We define a direction (from the smalest index to the greatest) --*/ change_face_orientation = false; if (face_iPoint > face_jPoint) change_face_orientation = true; iEdge = FindEdge(face_iPoint, face_jPoint); - + for (iDim = 0; iDim < nDim; iDim++) { Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); @@ -12154,7 +8382,7 @@ void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); } - + switch (nDim) { case 2: /*--- Two dimensional problem ---*/ @@ -12177,7 +8405,7 @@ void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) } } } - + /*--- Check if there is a normal with null area ---*/ for (iEdge = 0; iEdge < (long)nEdge; iEdge++) { NormalFace = edge[iEdge]->GetNormal(); @@ -12185,21 +8413,21 @@ void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) Area = sqrt(Area); if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; } - - + + #ifdef HAVE_MPI SU2_MPI::Allreduce(&my_DomainVolume, &DomainVolume, 1, MPI_DOUBLE, MPI_SUM, MPI_COMM_WORLD); #else DomainVolume = my_DomainVolume; #endif - + if ((rank == MASTER_NODE) && (action == ALLOCATE)) { if (nDim == 2) cout <<"Area of the computational grid: "<< DomainVolume <<"."<< endl; if (nDim == 3) cout <<"Volume of the computational grid: "<< DomainVolume <<"."<< endl; } - + config->SetDomainVolume(DomainVolume); - + delete[] Coord_Edge_CG; delete[] Coord_FaceElem_CG; delete[] Coord_Elem_CG; @@ -12208,10 +8436,10 @@ void CPhysicalGeometry::SetControlVolume(CConfig *config, unsigned short action) } void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short action) { - + /*--- This routine is only meant for visualization in serial currently ---*/ #ifndef HAVE_MPI - + unsigned long face_iPoint = 0, face_jPoint = 0, iElem, iPoint_Viz; long iEdge; unsigned short nEdgesFace = 1, iFace, iEdgesFace, iDim; @@ -12223,41 +8451,41 @@ void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short a string mesh_filename; vector X, Y, Z, X_n, Y_n, Z_n; su2double r1[3], r2[3], CrossProduct[3]; - + /*--- Access the point number for control volume we want to vizualize ---*/ - + iPoint_Viz = config->GetVisualize_CV(); - + /*--- Allocate some structures for building the dual CVs ---*/ - + Coord_Edge_CG = new su2double [nDim]; Coord_FaceElem_CG = new su2double [nDim]; Coord_Elem_CG = new su2double [nDim]; Coord_FaceiPoint = new su2double [nDim]; Coord_FacejPoint = new su2double [nDim]; - + /*--- Loop over each face of each element ---*/ - + CrossProduct[0] = 0.0; CrossProduct[1] = 0.0; CrossProduct[2] = 0.0; - + for (iElem = 0; iElem < nElem; iElem++) { - + for (iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { - + /*--- In 2D all the faces have only one edge ---*/ if (nDim == 2) nEdgesFace = 1; /*--- In 3D the number of edges per face is the same as the number of point per face ---*/ if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); - + /*-- Loop over the edges of a face ---*/ for (iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { - + /*--- In 2D only one edge (two points) per edge ---*/ if (nDim == 2) { face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); } - + /*--- In 3D there are several edges in each face ---*/ if (nDim == 3) { face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); @@ -12266,10 +8494,10 @@ void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short a else face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); } - + /*--- We define a direction (from the smallest index to the greatest) --*/ iEdge = FindEdge(face_iPoint, face_jPoint); - + for (iDim = 0; iDim < nDim; iDim++) { Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); @@ -12277,7 +8505,7 @@ void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short a Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); } - + /*--- Print out the coordinates for a set of triangles making up a single dual control volume for visualization. ---*/ @@ -12304,16 +8532,16 @@ void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short a } } } - + /*--- Write a Tecplot file to visualize the CV ---*/ - + strcpy(cstr,"dual_cv"); SPRINTF (buffer, "_%d.dat", SU2_TYPE::Int(iPoint_Viz)); strcat(cstr, buffer); - + Tecplot_File.open(cstr, ios::out); Tecplot_File << "TITLE= \"Visualization of the control volume\"" << endl; - + if (nDim == 2) { Tecplot_File << "VARIABLES = \"x\",\"y\" " << endl; Tecplot_File << "ZONE NODES= "<< counter*2 <<", ELEMENTS= "; @@ -12323,18 +8551,18 @@ void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short a Tecplot_File << "ZONE NODES= "<< counter*3 <<", ELEMENTS= "; Tecplot_File << counter <<", DATAPACKING=POINT, ZONETYPE=FEBRICK"<< endl; } - + /*--- Write coordinates for the nodes in the order that they were found for each of the edges/triangles making up a dual control volume. ---*/ - + for (vector::size_type i = 0; i != X.size(); i++) { Tecplot_File << X[i] << "\t" << Y[i]; if (nDim == 3) Tecplot_File << "\t" << Z[i]; Tecplot_File << "\n"; } - + /*--- Create a new connectivity table in the order the faces were found ---*/ - + int j; for (int i= 0; i < counter; i++) { if (nDim == 2) { @@ -12346,18 +8574,18 @@ void CPhysicalGeometry::VisualizeControlVolume(CConfig *config, unsigned short a Tecplot_File << j+3<<"\t" <GetNode(iNodes); output_file << "\t"<GetGlobalIndex() << endl; #endif - + } - + /*--- Loop through and write the boundary info ---*/ - + output_file << "NMARK= " << nMarker << endl; for (iMarker = 0; iMarker < nMarker; iMarker++) { - + /*--- Ignore SEND_RECEIVE for the moment ---*/ if (bound[iMarker][0]->GetVTK_Type() != VERTEX) { - + Grid_Marker = config->GetMarker_All_TagBound(iMarker); output_file << "MARKER_TAG= " << Grid_Marker << endl; output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; - + if (nDim == 2) { for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; @@ -12423,7 +8651,7 @@ void CPhysicalGeometry::SetMeshFile (CConfig *config, string val_mesh_out_filena output_file << iElem_Bound << endl; } } - + if (nDim == 3) { for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" ; @@ -12432,22 +8660,22 @@ void CPhysicalGeometry::SetMeshFile (CConfig *config, string val_mesh_out_filena output_file << iElem_Bound << endl; } } - + } else if (bound[iMarker][0]->GetVTK_Type() == VERTEX) { output_file << "MARKER_TAG= SEND_RECEIVE" << endl; output_file << "MARKER_ELEMS= " << nElem_Bound[iMarker]<< endl; if (config->GetMarker_All_SendRecv(iMarker) > 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; if (config->GetMarker_All_SendRecv(iMarker) < 0) output_file << "SEND_TO= " << config->GetMarker_All_SendRecv(iMarker) << endl; - + for (iElem_Bound = 0; iElem_Bound < nElem_Bound[iMarker]; iElem_Bound++) { output_file << bound[iMarker][iElem_Bound]->GetVTK_Type() << "\t" << bound[iMarker][iElem_Bound]->GetNode(0) << "\t" << bound[iMarker][iElem_Bound]->GetRotation_Type() << endl; } - + } } - + output_file.close(); } @@ -12457,48 +8685,48 @@ void CPhysicalGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2doubl unsigned long iEdge, iPoint, jPoint, iVertex; su2double eps = 1E-6; bool NearField = false; - + Coord = new su2double [nDim]; - + for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { su2double *Coord = node[iPoint]->GetCoord(); node[iPoint]->SetCoord_Old(Coord); } - + /*--- Jacobi iterations ---*/ for (iSmooth = 0; iSmooth < val_nSmooth; iSmooth++) { - + for (iPoint = 0; iPoint < nPoint; iPoint++) node[iPoint]->SetCoord_SumZero(); - - + + /*--- Loop over Interior edges ---*/ for (iEdge = 0; iEdge < nEdge; iEdge++) { iPoint = edge[iEdge]->GetNode(0); Coord_i = node[iPoint]->GetCoord(); - + jPoint = edge[iEdge]->GetNode(1); Coord_j = node[jPoint]->GetCoord(); - + /*--- Accumulate nearest neighbor Coord to Res_sum for each variable ---*/ node[iPoint]->AddCoord_Sum(Coord_j); node[jPoint]->AddCoord_Sum(Coord_i); - + } - + /*--- Loop over all mesh points (Update Coords with averaged sum) ---*/ for (iPoint = 0; iPoint < nPoint; iPoint++) { nneigh = node[iPoint]->GetnPoint(); Coord_Sum = node[iPoint]->GetCoord_Sum(); Coord_Old = node[iPoint]->GetCoord_Old(); - + if (nDim == 2) { Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh)); Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh)); if ((NearField) && ((Coord_Old[1] > Position_Plane-eps) && (Coord_Old[1] < Position_Plane+eps))) Coord[1] = Coord_Old[1]; } - + if (nDim == 3) { Coord[0] =(Coord_Old[0] + val_smooth_coeff*Coord_Sum[0]) /(1.0 + val_smooth_coeff*su2double(nneigh)); Coord[1] =(Coord_Old[1] + val_smooth_coeff*Coord_Sum[1]) /(1.0 + val_smooth_coeff*su2double(nneigh)); @@ -12506,10 +8734,10 @@ void CPhysicalGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2doubl if ((NearField) && ((Coord_Old[2] > Position_Plane-eps) && (Coord_Old[2] < Position_Plane+eps))) Coord[2] = Coord_Old[2]; } - + node[iPoint]->SetCoord(Coord); } - + /*--- Copy boundary values ---*/ for (iMarker = 0; iMarker < nMarker; iMarker++) for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { @@ -12518,13 +8746,13 @@ void CPhysicalGeometry::SetCoord_Smoothing (unsigned short val_nSmooth, su2doubl node[iPoint]->SetCoord(Coord_Old); } } - + delete[] Coord; } bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_elem, unsigned short &face_first_elem, unsigned short &face_second_elem) { - + /*--- Find repeated nodes between two elements to identify the common face ---*/ unsigned long iPoint = 0, jPoint = 0; unsigned short face_node, iFace, iNode, jNode, nNodesFace; @@ -12532,9 +8760,9 @@ bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_ vector::iterator IterPoint; pair::iterator, vector ::iterator> mypair; bool face_first_found = false, face_second_found =false; - + if (first_elem == second_elem) return false; - + for (iNode = 0; iNode < elem[first_elem]->GetnNodes(); iNode++) { iPoint = elem[first_elem]->GetNode(iNode); for (jNode = 0; jNode < elem[second_elem]->GetnNodes(); jNode++) { @@ -12545,34 +8773,34 @@ bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_ } } } - + /*--- Sort point in face and check that the list is unique ---*/ sort( CommonPoints.begin(), CommonPoints.end()); IterPoint = unique( CommonPoints.begin(), CommonPoints.end()); CommonPoints.resize( distance(CommonPoints.begin(), IterPoint) ); - + /*--- In 2D, the two elements must share two points that make up an edge, as all "faces" are edges in 2D. In 3D, we need to find exactly 3 (tri) or 4 (quad) common points. Return immediately to avoid a memory issue due to vectors of different lengths below. ---*/ - + if ((nDim == 2) && (CommonPoints.size() != 2)) return false; if ((nDim == 3) && ((CommonPoints.size() != 3) && (CommonPoints.size() != 4))) return false; - + /*--- Search the sequence in the first element ---*/ for (iFace = 0; iFace < elem[first_elem]->GetnFaces(); iFace++) { nNodesFace = elem[first_elem]->GetnNodesFace(iFace); - + if (nNodesFace == CommonPoints.size()) { for (iNode = 0; iNode < nNodesFace; iNode++) { face_node = elem[first_elem]->GetFaces(iFace, iNode); PointFaceFirst.push_back(elem[first_elem]->GetNode(face_node)); } - + /*--- Sort face_poin to perform comparison ---*/ sort( PointFaceFirst.begin(), PointFaceFirst.end()); - + /*--- List comparison ---*/ mypair = mismatch (PointFaceFirst.begin(), PointFaceFirst.end(), CommonPoints.begin()); if (mypair.first == PointFaceFirst.end()) { @@ -12580,24 +8808,24 @@ bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_ face_first_found = true; break; } - + PointFaceFirst.erase (PointFaceFirst.begin(), PointFaceFirst.end()); } } - + /*--- Search the secuence in the second element ---*/ for (iFace = 0; iFace < elem[second_elem]->GetnFaces(); iFace++) { nNodesFace = elem[second_elem]->GetnNodesFace(iFace); - + if (nNodesFace == CommonPoints.size()) { for (iNode = 0; iNode < nNodesFace; iNode++) { face_node = elem[second_elem]->GetFaces(iFace, iNode); PointFaceSecond.push_back(elem[second_elem]->GetNode(face_node)); } - + /*--- Sort face_poin to perform comparison ---*/ sort( PointFaceSecond.begin(), PointFaceSecond.end()); - + /*--- List comparison ---*/ mypair = mismatch (PointFaceSecond.begin(), PointFaceSecond.end(), CommonPoints.begin()); if (mypair.first == PointFaceSecond.end()) { @@ -12605,24 +8833,24 @@ bool CPhysicalGeometry::FindFace(unsigned long first_elem, unsigned long second_ face_second_found = true; break; } - + PointFaceSecond.erase (PointFaceSecond.begin(), PointFaceSecond.end()); } } - + if (face_first_found && face_second_found) return true; else return false; - + } void CPhysicalGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file) { - + unsigned long iElem, iPoint; unsigned short iDim; ofstream Tecplot_File; - + /*--- Open the tecplot file and write the header ---*/ - + if (new_file) { Tecplot_File.open(mesh_filename, ios::out); Tecplot_File << "TITLE= \"Visualization of the volumetric grid\"" << endl; @@ -12630,24 +8858,24 @@ void CPhysicalGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; } else Tecplot_File.open(mesh_filename, ios::out | ios::app); - + Tecplot_File << "ZONE T= "; if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; else Tecplot_File << "\"Deformed grid\", C=RED, "; Tecplot_File << "NODES= "<< nPoint <<", ELEMENTS= "<< nElem <<", DATAPACKING= POINT"; if (nDim == 2) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; if (nDim == 3) Tecplot_File << ", ZONETYPE= FEBRICK"<< endl; - + /*--- Adding coordinates ---*/ - + for (iPoint = 0; iPoint < nPoint; iPoint++) { for (iDim = 0; iDim < nDim; iDim++) Tecplot_File << scientific << node[iPoint]->GetCoord(iDim) << "\t"; Tecplot_File << "\n"; } - + /*--- Adding conectivity ---*/ - + for (iElem = 0; iElem < nElem; iElem++) { if (elem[iElem]->GetVTK_Type() == TRIANGLE) { Tecplot_File << @@ -12688,37 +8916,37 @@ void CPhysicalGeometry::SetTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new elem[iElem]->GetNode(4)+1 <<" "<< elem[iElem]->GetNode(5)+1 << endl; } } - + Tecplot_File.close(); } void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], bool new_file, CConfig *config) { - + ofstream Tecplot_File; unsigned long iPoint, Total_nElem_Bound, iElem, *PointSurface = NULL, nPointSurface = 0; unsigned short Coord_i, iMarker; - + /*--- It is important to do a renumbering to don't add points that do not belong to the surfaces ---*/ - + PointSurface = new unsigned long[nPoint]; for (iPoint = 0; iPoint < nPoint; iPoint++) if (node[iPoint]->GetBoundary()) { PointSurface[iPoint] = nPointSurface; nPointSurface++; } - + /*--- Compute the total number of elements ---*/ - + Total_nElem_Bound = 0; for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { if (config->GetMarker_All_Plotting(iMarker) == YES) { Total_nElem_Bound += nElem_Bound[iMarker]; } } - + /*--- Open the tecplot file and write the header ---*/ - + if (new_file) { Tecplot_File.open(mesh_filename, ios::out); Tecplot_File << "TITLE= \"Visualization of the surface grid\"" << endl; @@ -12726,20 +8954,20 @@ void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], boo if (nDim == 3) Tecplot_File << "VARIABLES = \"x\",\"y\",\"z\" " << endl; } else Tecplot_File.open(mesh_filename, ios::out | ios::app); - + if (Total_nElem_Bound != 0) { - + /*--- Write the header of the file ---*/ - + Tecplot_File << "ZONE T= "; if (new_file) Tecplot_File << "\"Original grid\", C=BLACK, "; else Tecplot_File << "\"Deformed grid\", C=RED, "; Tecplot_File << "NODES= "<< nPointSurface <<", ELEMENTS= "<< Total_nElem_Bound <<", DATAPACKING= POINT"; if (nDim == 2) Tecplot_File << ", ZONETYPE= FELINESEG"<< endl; if (nDim == 3) Tecplot_File << ", ZONETYPE= FEQUADRILATERAL"<< endl; - + /*--- Only write the coordiantes of the points that are on the surfaces ---*/ - + if (nDim == 3) { for (iPoint = 0; iPoint < nPoint; iPoint++) if (node[iPoint]->GetBoundary()) { @@ -12756,9 +8984,9 @@ void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], boo Tecplot_File << "\n"; } } - + /*--- Write the cells using the new numbering ---*/ - + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) if (config->GetMarker_All_Plotting(iMarker) == YES) for (iElem = 0; iElem < nElem_Bound[iMarker]; iElem++) { @@ -12783,9 +9011,9 @@ void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], boo } } else { - + /*--- No elements in the surface ---*/ - + if (nDim == 2) { Tecplot_File << "ZONE NODES= 1, ELEMENTS= 1, DATAPACKING=POINT, ZONETYPE=FELINESEG"<< endl; Tecplot_File << "0.0 0.0"<< endl; @@ -12797,49 +9025,49 @@ void CPhysicalGeometry::SetBoundTecPlot(char mesh_filename[MAX_STRING_SIZE], boo Tecplot_File << "1 1 1 1"<< endl; } } - + /*--- Dealocate memory and close the file ---*/ - + delete[] PointSurface; Tecplot_File.close(); - + } void CPhysicalGeometry::SetColorGrid_Parallel(CConfig *config) { - + /*--- Initialize the color vector ---*/ - + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) node[iPoint]->SetColor(0); - + /*--- We need to have parallel support with MPI and have the ParMETIS library compiled and linked for parallel graph partitioning. ---*/ - + #ifdef HAVE_MPI #ifdef HAVE_PARMETIS - + MPI_Comm comm = MPI_COMM_WORLD; /*--- Linear partitioner object to help prepare parmetis data. ---*/ - + CLinearPartitioner pointPartitioner(Global_nPointDomain,0); - + /*--- Only call ParMETIS if we have more than one rank to avoid errors ---*/ - + if (size > SINGLE_NODE) { - + /*--- Create some structures that ParMETIS needs for partitioning. ---*/ - + idx_t numflag, nparts, edgecut, wgtflag, ncon; - + idx_t *vtxdist = new idx_t[size+1]; idx_t *part = new idx_t[nPoint]; - + real_t ubvec; real_t *tpwgts = new real_t[size]; - + /*--- Some recommended defaults for the various ParMETIS options. ---*/ - + wgtflag = 0; numflag = 0; ncon = 1; @@ -12848,21 +9076,21 @@ void CPhysicalGeometry::SetColorGrid_Parallel(CConfig *config) { idx_t options[METIS_NOPTIONS]; METIS_SetDefaultOptions(options); options[1] = 0; - + /*--- Fill the necessary ParMETIS data arrays. We do not apply any weighting during the partitioning process. ---*/ - + for (int i = 0; i < size; i++) { tpwgts[i] = 1.0/((real_t)size); } - + vtxdist[0] = 0; for (int i = 0; i < size; i++) { vtxdist[i+1] = (idx_t)pointPartitioner.GetLastIndexOnRank(i); } - + /*--- Calling ParMETIS ---*/ - + if (rank == MASTER_NODE) cout << "Calling ParMETIS..."; ParMETIS_V3_PartKway(vtxdist, xadj, adjacency, NULL, NULL, &wgtflag, &numflag, &ncon, &nparts, tpwgts, &ubvec, options, @@ -12871,78 +9099,78 @@ void CPhysicalGeometry::SetColorGrid_Parallel(CConfig *config) { cout << " graph partitioning complete ("; cout << edgecut << " edge cuts)." << endl; } - + /*--- Store the results of the partitioning (note that this is local since each processor is calling ParMETIS in parallel and storing the results for its initial piece of the grid. ---*/ - + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { node[iPoint]->SetColor(part[iPoint]); } - + /*--- Free all memory needed for the ParMETIS structures ---*/ - + if (vtxdist != NULL) delete [] vtxdist; if (part != NULL) delete [] part; if (tpwgts != NULL) delete [] tpwgts; - + } - + /*--- Delete the memory from the geometry class that carried the adjacency structure. ---*/ - + if (xadj != NULL) delete [] xadj; if (adjacency != NULL) delete [] adjacency; - + #endif #endif - + } void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { - + /*--- Resize our vectors for the 3 metrics: orthogonality, aspect ratio, and volume ratio. All are vertex-based for the dual CV. ---*/ - + Orthogonality.resize(nPoint,0.0); Aspect_Ratio.resize(nPoint,0.0); Volume_Ratio.resize(nPoint,0.0); - + /*--- Helper vectors for holding intermediate values. ---*/ - + vector SurfaceArea(nPoint,0.0); vector Area_Max(nPoint,0.0); vector Area_Min(nPoint,1.e6); vector SubVolume_Max(nPoint,0.0); vector SubVolume_Min(nPoint,1.e6); - + /*--- Orthogonality and aspect ratio (areas) are computed by looping over all edges to check the angles and the face areas. ---*/ - + for (unsigned long iEdge = 0; iEdge < nEdge; iEdge++) { - + /*--- Point identification, edge normal vector and area ---*/ - + const unsigned long iPoint = edge[iEdge]->GetNode(0); const unsigned long jPoint = edge[iEdge]->GetNode(1); - + const unsigned long GlobalIndex_i = node[iPoint]->GetGlobalIndex(); const unsigned long GlobalIndex_j = node[iPoint]->GetGlobalIndex(); - + /*-- Area normal for the current edge. Recall that this normal is computed by summing the normals of adjacent faces along the edge between iPoint & jPoint. ---*/ - + const su2double *Normal = edge[iEdge]->GetNormal(); - + /*--- Get the coordinates for point i & j. ---*/ - + const su2double *Coord_i = node[iPoint]->GetCoord(); const su2double *Coord_j = node[jPoint]->GetCoord(); /*--- Compute the vector pointing from iPoint to jPoint and its distance. We also compute face area (norm of the normal vector). ---*/ - + su2double distance = 0.0; su2double area = 0.0; vector edgeVector(nDim); @@ -12958,17 +9186,17 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { faces making up the boundary of the dual CV and is a measure of the aspect ratio of the dual control volume. Smaller is better (closer to isotropic). ----*/ - + if (node[iPoint]->GetDomain()) { Area_Min[iPoint] = min(Area_Min[iPoint], area); Area_Max[iPoint] = max(Area_Max[iPoint], area); } - + if (node[jPoint]->GetDomain()) { Area_Min[jPoint] = min(Area_Min[jPoint], area); Area_Max[jPoint] = max(Area_Max[jPoint], area); } - + if (area <= 0.0) { char buf[200]; SPRINTF(buf, "Zero-area CV face found for edge (%lu,%lu).", @@ -12978,19 +9206,19 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { /*--- Compute the angle between the unit normal associated with the edge and the unit vector pointing from iPoint to jPoint. ---*/ - + su2double dotProduct = 0.0; for (unsigned short iDim = 0; iDim < nDim; iDim++) { dotProduct += (Normal[iDim]/area)*(edgeVector[iDim]/distance); } - + /*--- The definition of orthogonality is an area-weighted average of 90 degrees minus the angle between the face area unit normal and the vector between i & j. If the two are perfectly aligned, then the orthogonality is the desired max of 90 degrees. If they are not aligned, the orthogonality will reduce from there. Good values are close to 90 degress, poor values are typically below 20 degress. ---*/ - + if (node[iPoint]->GetDomain()) { Orthogonality[iPoint] += area*(90.0 - acos(dotProduct)*180.0/PI_NUMBER); SurfaceArea[iPoint] += area; @@ -12999,92 +9227,92 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { Orthogonality[jPoint] += area*(90.0 - acos(dotProduct)*180.0/PI_NUMBER); SurfaceArea[jPoint] += area; } - + /*--- Error check for zero volume of the dual CVs. ---*/ - + if (node[iPoint]->GetVolume() <= 0.0) { char buf[200]; SPRINTF(buf, "Zero-area CV face found for point %lu.", GlobalIndex_i); SU2_MPI::Error(string(buf), CURRENT_FUNCTION); } - + if (node[jPoint]->GetVolume() <= 0.0) { char buf[200]; SPRINTF(buf, "Zero-area CV face found for point %lu.", GlobalIndex_j); SU2_MPI::Error(string(buf), CURRENT_FUNCTION); } - + } - + /*--- Loop boundary edges to include the area of the boundary elements. ---*/ - + for (unsigned short iMarker = 0; iMarker < nMarker; iMarker++) { if ((config->GetMarker_All_KindBC(iMarker) != INTERNAL_BOUNDARY) && (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE)){ - + for (unsigned long iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { const unsigned long iPoint = vertex[iMarker][iVertex]->GetNode(); const su2double *Normal = vertex[iMarker][iVertex]->GetNormal(); - + if (node[iPoint]->GetDomain()) { - + /*--- Face area (norm of the normal vector) ---*/ - + su2double area = 0.0; for (unsigned short iDim = 0; iDim < nDim; iDim++) area += Normal[iDim]*Normal[iDim]; area = sqrt(area); - + /*--- Check to store the area as the min or max for i or j. ---*/ - + Area_Min[iPoint] = min(Area_Min[iPoint], area); Area_Max[iPoint] = max(Area_Max[iPoint], area); - + } } } } - + /*--- Volume ratio is computed by looping over all volume elements and computing the sub-element volume contributions. The ratio between the largest and smallest sub-elements making up the dual CV is a measure of the volume stretching ratio for the cell. Smaller is better (closer to isotropic). ----*/ - + unsigned long face_iPoint = 0, face_jPoint = 0; unsigned short nEdgesFace = 1; - + vector Coord_Edge_CG(nDim); vector Coord_FaceElem_CG(nDim); vector Coord_Elem_CG(nDim); vector Coord_FaceiPoint(nDim); vector Coord_FacejPoint(nDim); - + for (unsigned long iElem = 0; iElem < nElem; iElem++) for (unsigned short iFace = 0; iFace < elem[iElem]->GetnFaces(); iFace++) { - + /*--- In 2D all the faces have only one edge ---*/ - + if (nDim == 2) nEdgesFace = 1; - + /*--- In 3D the number of edges per face is the same as the number of points per face. ---*/ - + if (nDim == 3) nEdgesFace = elem[iElem]->GetnNodesFace(iFace); - + /*-- Loop over the edges of a face ---*/ - + for (unsigned short iEdgesFace = 0; iEdgesFace < nEdgesFace; iEdgesFace++) { - + /*--- In 2D only one edge (two points) per edge ---*/ - + if (nDim == 2) { face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,1)); } - + /*--- In 3D there are several edges in each face ---*/ - + if (nDim == 3) { face_iPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace, iEdgesFace)); if (iEdgesFace != nEdgesFace-1) @@ -13092,13 +9320,13 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { else face_jPoint = elem[iElem]->GetNode(elem[iElem]->GetFaces(iFace,0)); } - + /*--- Locate the edge for the two selected points. ---*/ - + const unsigned long iEdge = FindEdge(face_iPoint, face_jPoint); - + /*--- Collect the CG and coordinates for this sub-element face. ---*/ - + for (unsigned short iDim = 0; iDim < nDim; iDim++) { Coord_Edge_CG[iDim] = edge[iEdge]->GetCG(iDim); Coord_Elem_CG[iDim] = elem[iElem]->GetCG(iDim); @@ -13106,13 +9334,13 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { Coord_FaceiPoint[iDim] = node[face_iPoint]->GetCoord(iDim); Coord_FacejPoint[iDim] = node[face_jPoint]->GetCoord(iDim); } - + /*--- Access the sub-volume of the element separately in 2D or 3D. ---*/ - + su2double Volume_i, Volume_j; switch (nDim) { case 2: - + Volume_i = edge[iEdge]->GetVolume(Coord_FaceiPoint.data(), Coord_Edge_CG.data(), Coord_Elem_CG.data()); @@ -13123,12 +9351,12 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { break; case 3: - + Volume_i = edge[iEdge]->GetVolume(Coord_FaceiPoint.data(), Coord_Edge_CG.data(), Coord_FaceElem_CG.data(), Coord_Elem_CG.data()); - + Volume_j = edge[iEdge]->GetVolume(Coord_FacejPoint.data(), Coord_Edge_CG.data(), Coord_FaceElem_CG.data(), @@ -13136,27 +9364,27 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { break; } - + /*--- Check if sub-elem volume is the min or max for iPoint. ---*/ if (node[face_iPoint]->GetDomain()) { SubVolume_Min[face_iPoint] = min(SubVolume_Min[face_iPoint], Volume_i); SubVolume_Max[face_iPoint] = max(SubVolume_Max[face_iPoint], Volume_i); } - + /*--- Check if sub-elem volume is the min or max for jPoint. ---*/ if (node[face_jPoint]->GetDomain()) { SubVolume_Min[face_jPoint] = min(SubVolume_Min[face_jPoint], Volume_j); SubVolume_Max[face_jPoint] = max(SubVolume_Max[face_jPoint], Volume_j); } - + } } - + /*--- Compute the metrics with a final loop over the vertices. Also compute the local min and max values here for reporting. ---*/ - + su2double orthoMin = 1.e6, arMin = 1.e6, vrMin = 1.e6; su2double orthoMax = 0.0, arMax = 0.0, vrMax = 0.0; for (unsigned long iPoint= 0; iPoint < nPointDomain; iPoint++) { @@ -13167,34 +9395,34 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { Aspect_Ratio[iPoint] = Area_Max[iPoint]/Area_Min[iPoint]; arMin = min(Aspect_Ratio[iPoint], arMin); arMax = max(Aspect_Ratio[iPoint], arMax); - + Volume_Ratio[iPoint] = SubVolume_Max[iPoint]/SubVolume_Min[iPoint]; vrMin = min(Volume_Ratio[iPoint], vrMin); vrMax = max(Volume_Ratio[iPoint], vrMax); } - + /*--- Reduction to find the min and max values globally. ---*/ - + su2double Global_Ortho_Min, Global_Ortho_Max; SU2_MPI::Allreduce(&orthoMin, &Global_Ortho_Min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); SU2_MPI::Allreduce(&orthoMax, &Global_Ortho_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - + su2double Global_AR_Min, Global_AR_Max; SU2_MPI::Allreduce(&arMin, &Global_AR_Min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); SU2_MPI::Allreduce(&arMax, &Global_AR_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - + su2double Global_VR_Min, Global_VR_Max; SU2_MPI::Allreduce(&vrMin, &Global_VR_Min, 1, MPI_DOUBLE, MPI_MIN, MPI_COMM_WORLD); SU2_MPI::Allreduce(&vrMax, &Global_VR_Max, 1, MPI_DOUBLE, MPI_MAX, MPI_COMM_WORLD); - + /*--- Print the summary to the console for the user. ---*/ - + PrintingToolbox::CTablePrinter MetricsTable(&std::cout); MetricsTable.AddColumn("Mesh Quality Metric", 30); MetricsTable.AddColumn("Minimum", 15); @@ -13206,166 +9434,16 @@ void CPhysicalGeometry::ComputeMeshQualityStatistics(CConfig *config) { MetricsTable << "CV Sub-Volume Ratio" << Global_VR_Min << Global_VR_Max; MetricsTable.PrintFooter(); } - + /*--- If we will not be writing the stats to the visualization files, force clear the memory with the swap() function. ---*/ - - if (!config->GetWrt_MeshQuality()) { - vector().swap(Orthogonality); - vector().swap(Aspect_Ratio); - vector().swap(Volume_Ratio); - } - -} - -void CPhysicalGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print) { - - unsigned long iPoint; - su2double RotVel[3], Distance[3], *Coord, Center[3], Omega[3], L_Ref; - unsigned short iDim; - - /*--- Center of rotation & angular velocity vector from config ---*/ - - for (iDim = 0; iDim < 3; iDim++){ - Center[iDim] = config->GetMotion_Origin(iDim); - Omega[iDim] = config->GetRotation_Rate(iDim)/config->GetOmega_Ref(); - } - - L_Ref = config->GetLength_Ref(); - - /*--- Print some information to the console ---*/ - - if (rank == MASTER_NODE && print) { - cout << " Rotational origin (x, y, z): ( " << Center[0] << ", " << Center[1]; - cout << ", " << Center[2] << " )" << endl; - cout << " Angular velocity about x, y, z axes: ( " << Omega[0] << ", "; - cout << Omega[1] << ", " << Omega[2] << " ) rad/s" << endl; - } - - /*--- Loop over all nodes and set the rotational velocity ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Get the coordinates of the current node ---*/ - - Coord = node[iPoint]->GetCoord(); - - /*--- Calculate the non-dim. distance from the rotation center ---*/ - - Distance[0] = (Coord[0]-Center[0])/L_Ref; - Distance[1] = (Coord[1]-Center[1])/L_Ref; - Distance[2] = 0.0; - if (nDim == 3) - Distance[2] = (Coord[2]-Center[2])/L_Ref; - - /*--- Calculate the angular velocity as omega X r ---*/ - - RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); - RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); - RotVel[2] = 0.0; - if (nDim == 3) - RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); - - /*--- Store the grid velocity at this node ---*/ - - node[iPoint]->SetGridVel(RotVel); - - } - -} - -void CPhysicalGeometry::SetShroudVelocity(CConfig *config) { - - unsigned long iPoint, iVertex; - unsigned short iMarker, iMarkerShroud; - su2double RotVel[3]; - - RotVel[0] = 0.0; - RotVel[1] = 0.0; - RotVel[2] = 0.0; - - /*--- Loop over all vertex in the shroud marker and set the rotational velocity to 0.0 ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++){ - for(iMarkerShroud=0; iMarkerShroud < config->GetnMarker_Shroud(); iMarkerShroud++){ - if(config->GetMarker_Shroud(iMarkerShroud) == config->GetMarker_All_TagBound(iMarker)){ - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - node[iPoint]->SetGridVel(RotVel); - } - } - } - } -} - -void CPhysicalGeometry::SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print) { - - unsigned short iDim; - unsigned long iPoint; - su2double xDot[3] = {0.0,0.0,0.0}; - - /*--- Get the translational velocity vector from config ---*/ - for (iDim = 0; iDim < 3; iDim++){ - xDot[iDim] = config->GetTranslation_Rate(iDim)/config->GetVelocity_Ref(); - } - /*--- Print some information to the console ---*/ - - if (rank == MASTER_NODE && print) { - cout << " Non-dim. translational velocity: (" << xDot[0] << ", " << xDot[1]; - cout << ", " << xDot[2] << ")." << endl; - } - - /*--- Loop over all nodes and set the translational velocity ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) { - - /*--- Store the grid velocity at this node ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - node[iPoint]->SetGridVel(iDim,xDot[iDim]); - } - - } - -} -void CPhysicalGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { - - /*--- Local variables ---*/ - - su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; - su2double TimeStep, GridVel = 0.0; - unsigned long iPoint; - unsigned short iDim; - - /*--- Compute the velocity of each node in the volume mesh ---*/ - - for (iPoint = 0; iPoint < GetnPoint(); iPoint++) { - - /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ - - Coord_nM1 = node[iPoint]->GetCoord_n1(); - Coord_n = node[iPoint]->GetCoord_n(); - Coord_nP1 = node[iPoint]->GetCoord(); - - /*--- Unsteady time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - if (config->GetTime_Marching() == DT_STEPPING_1ST) - GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; - if (config->GetTime_Marching() == DT_STEPPING_2ND) - GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] - + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); - - /*--- Store grid velocity for this point ---*/ - - node[iPoint]->SetGridVel(iDim, GridVel); - } + if (!config->GetWrt_MeshQuality()) { + vector().swap(Orthogonality); + vector().swap(Aspect_Ratio); + vector().swap(Volume_Ratio); } - + } void CPhysicalGeometry::FindNormal_Neighbor(CConfig *config) { @@ -13373,18 +9451,18 @@ void CPhysicalGeometry::FindNormal_Neighbor(CConfig *config) { unsigned long Point_Normal, jPoint; unsigned short iNeigh, iMarker, iDim; unsigned long iPoint, iVertex; - + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - + if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { - + for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - + iPoint = vertex[iMarker][iVertex]->GetNode(); Normal = vertex[iMarker][iVertex]->GetNormal(); - + /*--- Compute closest normal neighbor, note that the normal are oriented inwards ---*/ Point_Normal = 0; cos_max = -1.0; for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { @@ -13399,7 +9477,7 @@ void CPhysicalGeometry::FindNormal_Neighbor(CConfig *config) { norm_vect = sqrt(norm_vect); norm_Normal = sqrt(norm_Normal); cos_alpha = scalar_prod/(norm_vect*norm_Normal); - + /*--- Get maximum cosine ---*/ if (cos_alpha >= cos_max) { Point_Normal = jPoint; @@ -13412,131 +9490,25 @@ void CPhysicalGeometry::FindNormal_Neighbor(CConfig *config) { } } -void CPhysicalGeometry::SetGeometryPlanes(CConfig *config) { - - bool loop_on; - unsigned short iMarker = 0; - su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; - unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; - - /*--- Compute the total number of points on the near-field ---*/ - nVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - nVertex_Wall += nVertex[iMarker]; - - - /*--- Create an array with all the coordinates, points, pressures, face area, - equivalent area, and nearfield weight ---*/ - Xcoord = new su2double[nVertex_Wall]; - Ycoord = new su2double[nVertex_Wall]; - if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; - FaceArea = new su2double[nVertex_Wall]; - - /*--- Copy the boundary information to an array ---*/ - iVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); - Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); - if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); - Face_Normal = vertex[iMarker][iVertex]->GetNormal(); - FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); - iVertex_Wall ++; - } - - - //vector XCoordList; - vector::iterator IterXCoordList; - - for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) - XCoordList.push_back(Xcoord[iVertex]); - - sort( XCoordList.begin(), XCoordList.end()); - IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); - XCoordList.resize( IterXCoordList - XCoordList.begin() ); - - /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ - Xcoord_plane.resize(XCoordList.size()); - Ycoord_plane.resize(XCoordList.size()); - if (nDim==3) Zcoord_plane.resize(XCoordList.size()); - FaceArea_plane.resize(XCoordList.size()); - Plane_points.resize(XCoordList.size()); - - - su2double dist_ratio; - unsigned long iCoord; - - /*--- Distribute the values among the different PhiAngles ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - if (node[iPoint]->GetDomain()) { - loop_on = true; - for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { - dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); - if (dist_ratio >= 0 && dist_ratio <= 1.0) { - if (dist_ratio <= 0.5) iCoord = ixCoord; - else iCoord = ixCoord+1; - Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); - Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); - if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); - FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION - Plane_points[iCoord].push_back(iPoint ); - loop_on = false; - } - } - } - } - - unsigned long auxPoint; - /*--- Order the arrays in ascending values of y ---*/ - for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) - for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) - for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) - if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { - auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord; - auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord; - auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint; - if (nDim==3) { - auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord; - } - auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea; - } - - /*--- Delete structures ---*/ - delete[] Xcoord; delete[] Ycoord; - if (Zcoord != NULL) delete[] Zcoord; - delete[] FaceArea; -} - void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { unsigned short iMarker, icommas; unsigned long iVertex, iPoint, (*Point2Vertex)[2], nPointLocal = 0, nPointGlobal = 0; su2double Sensitivity; bool *PointInDomain; - + nPointLocal = nPoint; -#ifdef HAVE_MPI SU2_MPI::Allreduce(&nPointLocal, &nPointGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - nPointGlobal = nPointLocal; -#endif - + Point2Vertex = new unsigned long[nPointGlobal][2]; PointInDomain = new bool[nPointGlobal]; - + for (iPoint = 0; iPoint < nPointGlobal; iPoint ++) PointInDomain[iPoint] = false; - + for (iMarker = 0; iMarker < nMarker; iMarker++) if (config->GetMarker_All_DV(iMarker) == YES) for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - + /*--- The sensitivity file uses the global numbering ---*/ iPoint = node[vertex[iMarker][iVertex]->GetNode()]->GetGlobalIndex(); @@ -13547,9 +9519,9 @@ void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { vertex[iMarker][iVertex]->SetAuxVar(0.0); } } - + /*--- Time-average any unsteady surface sensitivities ---*/ - + unsigned long iTimeIter, nTimeIter; su2double delta_T, total_T; if (config->GetTime_Marching() && config->GetTime_Domain()) { @@ -13557,31 +9529,31 @@ void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { delta_T = config->GetTime_Step(); total_T = (su2double)nTimeIter*delta_T; } else if (config->GetTime_Marching() == HARMONIC_BALANCE) { - + /*--- Compute period of oscillation & compute time interval using nTimeInstances ---*/ - + su2double period = config->GetHarmonicBalance_Period(); nTimeIter = config->GetnTimeInstances(); delta_T = period/(su2double)nTimeIter; total_T = period; - + } else { nTimeIter = 1; delta_T = 1.0; total_T = 1.0; } - + for (iTimeIter = 0; iTimeIter < nTimeIter; iTimeIter++) { - + /*--- Prepare to read surface sensitivity files (CSV) ---*/ - + string text_line; ifstream Surface_file; char buffer[50]; char cstr[MAX_STRING_SIZE]; string surfadj_filename = config->GetSurfAdjCoeff_FileName(); strcpy (cstr, surfadj_filename.c_str()); - + /*--- Write file name with extension if unsteady or steady ---*/ if (config->GetTime_Marching() == HARMONIC_BALANCE) SPRINTF (buffer, "_%d.csv", SU2_TYPE::Int(iTimeIter)); @@ -13596,36 +9568,36 @@ void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { } else SPRINTF (buffer, ".csv"); - + strcat (cstr, buffer); - + /*--- Read the sensitivity file ---*/ - + string::size_type position; - + Surface_file.open(cstr, ios::in); /*--- File header ---*/ - + getline(Surface_file, text_line); - + vector split_line; - + char delimiter = ','; split_line = PrintingToolbox::split(text_line, delimiter); - + for (unsigned short iField = 0; iField < split_line.size(); iField++){ PrintingToolbox::trim(split_line[iField]); } - + std::vector::iterator it = std::find(split_line.begin(), split_line.end(), "\"Surface_Sensitivity\""); - + if (it == split_line.end()){ SU2_MPI::Error("Surface sensitivity not found in file.", CURRENT_FUNCTION); } - + unsigned short sens_index = std::distance(split_line.begin(), it); - + while (getline(Surface_file, text_line)) { for (icommas = 0; icommas < 50; icommas++) { position = text_line.find( ",", 0 ); @@ -13633,35 +9605,35 @@ void CPhysicalGeometry::SetBoundSensitivity(CConfig *config) { } stringstream point_line(text_line); point_line >> iPoint; - + for (int i = 1; i <= sens_index; i++) point_line >> Sensitivity; - + if (PointInDomain[iPoint]) { - + /*--- Find the vertex for the Point and Marker ---*/ - + iMarker = Point2Vertex[iPoint][0]; iVertex = Point2Vertex[iPoint][1]; - + /*--- Increment the auxiliary variable with the contribution of this unsteady timestep. For steady problems, this reduces to a single sensitivity value multiplied by 1.0. ---*/ - + vertex[iMarker][iVertex]->AddAuxVar(Sensitivity*(delta_T/total_T)); } - + } Surface_file.close(); } - + delete[] Point2Vertex; delete[] PointInDomain; - + } void CPhysicalGeometry::SetSensitivity(CConfig *config) { - + ifstream restart_file; string filename = config->GetSolution_AdjFileName(); @@ -13670,7 +9642,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { unsigned long iPoint, index; string::size_type position; int counter = 0; - + Sensitivity = new su2double[nPoint*nDim]; if (config->GetTime_Domain()) { @@ -13678,14 +9650,14 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { }else { nTimeIter = 1; } - + if (rank == MASTER_NODE) cout << "Reading in sensitivity at iteration " << nTimeIter-1 << "."<< endl; - + /*--- Read all lines in the restart file ---*/ long iPoint_Local; unsigned long iPoint_Global = 0; string text_line; - - + + for (iPoint = 0; iPoint < nPoint; iPoint++) { for (iDim = 0; iDim < nDim; iDim++) { Sensitivity[iPoint*nDim+iDim] = 0.0; @@ -13697,10 +9669,10 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { filename = config->GetSolution_AdjFileName(); filename = config->GetObjFunc_Extension(filename); - + if (config->GetRead_Binary_Restart()) { - + filename = config->GetFilename(filename, ".dat", nTimeIter-1); char str_buf[CGNS_STRING_SIZE], fname[100]; @@ -13808,7 +9780,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { string field_buf; int ierr; - + /*--- All ranks open the file using MPI. ---*/ ierr = MPI_File_open(MPI_COMM_WORLD, fname, MPI_MODE_RDONLY, MPI_INFO_NULL, &fhw); @@ -13822,7 +9794,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { /*--- First, read the number of variables and points (i.e., cols and rows), which we will need in order to read the file later. Also, read the variable string names here. Only the master rank reads the header. ---*/ - + if (rank == MASTER_NODE) MPI_File_read(fhw, Restart_Vars, nRestart_Vars, MPI_INT, MPI_STATUS_IGNORE); @@ -13834,10 +9806,10 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { have the hex representation of "SU2" as the first int in the file. ---*/ if (Restart_Vars[0] != 535532) { - + SU2_MPI::Error(string("File ") + string(fname) + string(" is not a binary SU2 restart file.\n") + - string("SU2 reads/writes binary restart files by default.\n") + - string("Note that backward compatibility for ASCII restart files is\n") + + string("SU2 reads/writes binary restart files by default.\n") + + string("Note that backward compatibility for ASCII restart files is\n") + string("possible with the WRT_BINARY_RESTART / READ_BINARY_RESTART options."), CURRENT_FUNCTION); } @@ -13918,7 +9890,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { Restart_Data = new passivedouble[nFields*GetnPointDomain()]; /*--- Collective call for all ranks to read from their view simultaneously. ---*/ - + MPI_File_read_all(fhw, Restart_Data, nFields*GetnPointDomain(), MPI_DOUBLE, &status); /*--- Free the derived datatype. ---*/ @@ -13959,35 +9931,35 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { SU2_MPI::Bcast(Restart_Meta, 8, MPI_DOUBLE, MASTER_NODE, MPI_COMM_WORLD); /*--- All ranks close the file after writing. ---*/ - + MPI_File_close(&fhw); - + delete [] blocklen; delete [] displace; - + #endif - + std::vector::iterator itx = std::find(config->fields.begin(), config->fields.end(), "\"Sensitivity_x\""); std::vector::iterator ity = std::find(config->fields.begin(), config->fields.end(), "\"Sensitivity_y\""); std::vector::iterator itz = std::find(config->fields.begin(), config->fields.end(), "\"Sensitivity_z\""); - + if (itx == config->fields.end()){ - SU2_MPI::Error("Sensitivity x not found in file.", CURRENT_FUNCTION); + SU2_MPI::Error("Sensitivity x not found in file.", CURRENT_FUNCTION); } if (ity == config->fields.end()){ - SU2_MPI::Error("Sensitivity y not found in file.", CURRENT_FUNCTION); + SU2_MPI::Error("Sensitivity y not found in file.", CURRENT_FUNCTION); } if (nDim == 3){ if (itz == config->fields.end()){ - SU2_MPI::Error("Sensitivity z not found in file.", CURRENT_FUNCTION); + SU2_MPI::Error("Sensitivity z not found in file.", CURRENT_FUNCTION); } } - - unsigned short sens_x_idx = std::distance(config->fields.begin(), itx); - unsigned short sens_y_idx = std::distance(config->fields.begin(), ity); + + unsigned short sens_x_idx = std::distance(config->fields.begin(), itx); + unsigned short sens_y_idx = std::distance(config->fields.begin(), ity); unsigned short sens_z_idx = 0; if (nDim == 3) - sens_z_idx = std::distance(config->fields.begin(), itz); + sens_z_idx = std::distance(config->fields.begin(), itz); /*--- Load the data from the binary restart. ---*/ @@ -14005,13 +9977,13 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { offset in the buffer of data from the restart file and load it. ---*/ index = counter*nFields + sens_x_idx - 1; - Sensitivity[iPoint_Local*nDim+0] = Restart_Data[index]; + Sensitivity[iPoint_Local*nDim+0] = Restart_Data[index]; index = counter*nFields + sens_y_idx - 1; - Sensitivity[iPoint_Local*nDim+1] = Restart_Data[index]; - + Sensitivity[iPoint_Local*nDim+1] = Restart_Data[index]; + if (nDim == 3){ index = counter*nFields + sens_z_idx - 1; - Sensitivity[iPoint_Local*nDim+2] = Restart_Data[index]; + Sensitivity[iPoint_Local*nDim+2] = Restart_Data[index]; } /*--- Increment the overall counter for how many points have been loaded. ---*/ counter++; @@ -14023,7 +9995,7 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { config->SetAoA_Sens(Restart_Meta[4]); } else { - + filename = config->GetFilename(filename, ".csv", nTimeIter-1); /*--- First, check that this is not a binary restart file. ---*/ @@ -14095,59 +10067,59 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { have the hex representation of "SU2" as the first int in the file. ---*/ if (magic_number == 535532) { - + SU2_MPI::Error(string("File ") + string(fname) + string(" is a binary SU2 restart file, expected ASCII.\n") + - string("SU2 reads/writes binary restart files by default.\n") + - string("Note that backward compatibility for ASCII restart files is\n") + + string("SU2 reads/writes binary restart files by default.\n") + + string("Note that backward compatibility for ASCII restart files is\n") + string("possible with the WRT_BINARY_RESTART / READ_BINARY_RESTART options."), CURRENT_FUNCTION); } - + MPI_File_close(&fhw); - + #endif restart_file.open(filename.data(), ios::in); if (restart_file.fail()) { SU2_MPI::Error(string("There is no adjoint restart file ") + filename, CURRENT_FUNCTION); } - + /*--- The first line is the header ---*/ getline (restart_file, text_line); - + vector fields = PrintingToolbox::split(text_line, ','); - + for (unsigned short iField = 0; iField < fields.size(); iField++){ PrintingToolbox::trim(fields[iField]); } - + std::vector::iterator itx = std::find(fields.begin(), fields.end(), "\"Sensitivity_x\""); std::vector::iterator ity = std::find(fields.begin(), fields.end(), "\"Sensitivity_y\""); std::vector::iterator itz = std::find(fields.begin(), fields.end(), "\"Sensitivity_z\""); - + if (itx == fields.end()){ - SU2_MPI::Error("Sensitivity x not found in file.", CURRENT_FUNCTION); + SU2_MPI::Error("Sensitivity x not found in file.", CURRENT_FUNCTION); } if (ity ==fields.end()){ - SU2_MPI::Error("Sensitivity y not found in file.", CURRENT_FUNCTION); + SU2_MPI::Error("Sensitivity y not found in file.", CURRENT_FUNCTION); } if (nDim == 3){ if (itz == fields.end()){ - SU2_MPI::Error("Sensitivity z not found in file.", CURRENT_FUNCTION); + SU2_MPI::Error("Sensitivity z not found in file.", CURRENT_FUNCTION); } } - - unsigned short sens_x_idx = std::distance(fields.begin(), itx); - unsigned short sens_y_idx = std::distance(fields.begin(), ity); + + unsigned short sens_x_idx = std::distance(fields.begin(), itx); + unsigned short sens_y_idx = std::distance(fields.begin(), ity); unsigned short sens_z_idx = 0; if (nDim == 3) - sens_z_idx = std::distance(fields.begin(), itz); - - + sens_z_idx = std::distance(fields.begin(), itz); + + for (iPoint_Global = 0; iPoint_Global < GetGlobal_nPointDomain(); iPoint_Global++ ) { getline (restart_file, text_line); - + vector point_line = PrintingToolbox::split(text_line, ','); /*--- Retrieve local index. If this node from the restart file lives @@ -14160,13 +10132,13 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { Sensitivity[iPoint_Local*nDim+1] = PrintingToolbox::stod(point_line[sens_y_idx]); if (nDim == 3) Sensitivity[iPoint_Local*nDim+2] = PrintingToolbox::stod(point_line[sens_z_idx]); - + } } - + /*--- Read AoA sensitivity ---*/ - + while (getline (restart_file, text_line)) { position = text_line.find ("SENS_AOA=",0); if (position != string::npos) { @@ -14174,30 +10146,30 @@ void CPhysicalGeometry::SetSensitivity(CConfig *config) { config->SetAoA_Sens(AoASens); } } - + restart_file.close(); } - + } void CPhysicalGeometry::ReadUnorderedSensitivity(CConfig *config) { - + /*--- This routine makes SU2_DOT more interoperable with other packages so that folks can customize their workflows. For example, one may want to compute flow and adjoint with package A, deform the mesh and project the sensitivities with SU2, and control the actual shape parameterization with package C. This routine allows SU2_DOT to read in an additional format for volume sensitivities that looks like: - + x0, y0, z0, dj/dx, dj/dy, dj/dz x1, y1, z1, dj/dx, dj/dy, dj/dz ... xN, yN, zN, dj/dx, dj/dy, dj/dz - + with N being the number of grid points. This is a format already used in other packages. Note that the nodes can be in any order in the file. ---*/ - + unsigned short iDim; unsigned long iPoint, pointID; unsigned long unmatched = 0, iPoint_Found = 0, iPoint_Ext = 0; @@ -14205,128 +10177,128 @@ void CPhysicalGeometry::ReadUnorderedSensitivity(CConfig *config) { su2double Coor_External[3] = {0.0,0.0,0.0}, Sens_External[3] = {0.0,0.0,0.0}; su2double dist; int rankID; - + string filename, text_line; ifstream external_file; ofstream sens_file; - + if (rank == MASTER_NODE) cout << "Parsing unordered ASCII volume sensitivity file."<< endl; - + /*--- Allocate space for the sensitivity and initialize. ---*/ - + Sensitivity = new su2double[nPoint*nDim]; for (iPoint = 0; iPoint < nPoint; iPoint++) { for (iDim = 0; iDim < nDim; iDim++) { Sensitivity[iPoint*nDim+iDim] = 0.0; } } - + /*--- Get the filename for the unordered ASCII sensitivity file input. ---*/ - + filename = config->GetDV_Unordered_Sens_Filename(); external_file.open(filename.data(), ios::in); if (external_file.fail()) { SU2_MPI::Error(string("There is no unordered ASCII sensitivity file ") + filename, CURRENT_FUNCTION); } - + /*--- Allocate the vectors to hold boundary node coordinates and its local ID. ---*/ - + vector Coords(nDim*nPointDomain); vector PointIDs(nPointDomain); - + /*--- Retrieve and store the coordinates of owned interior nodes and their local point IDs. ---*/ - + for (iPoint = 0; iPoint < nPointDomain; iPoint++) { PointIDs[iPoint] = iPoint; for (iDim = 0; iDim < nDim; iDim++) Coords[iPoint*nDim + iDim] = node[iPoint]->GetCoord(iDim); } - + /*--- Build the ADT of all interior nodes. ---*/ - + CADTPointsOnlyClass VertexADT(nDim, nPointDomain, Coords.data(), PointIDs.data(), true); - + /*--- Loop over all interior mesh nodes owned by this rank and find the matching point with minimum distance. Once we have the match, store the sensitivities from the file for that node. ---*/ - + if (VertexADT.IsEmpty()) { - + SU2_MPI::Error("No external points given to ADT.", CURRENT_FUNCTION); - + } else { - + /*--- Read the input sensitivity file and locate the point matches using the ADT search, on a line-by-line basis. ---*/ - + iPoint_Found = 0; iPoint_Ext = 0; while (getline (external_file, text_line)) { - + /*--- First, check that the line has 6 entries, otherwise throw out. ---*/ - + istringstream point_line(text_line); vector tokens((istream_iterator(point_line)), istream_iterator()); - + if (tokens.size() == 6) { - + istringstream point_line(text_line); - + /*--- Get the coordinates and sensitivity for this line. ---*/ - + for (iDim = 0; iDim < nDim; iDim++) point_line >> Coor_External[iDim]; for (iDim = 0; iDim < nDim; iDim++) point_line >> Sens_External[iDim]; - + /*--- Locate the nearest node to this external point. If it is on our rank, then store the sensitivity value. ---*/ - + VertexADT.DetermineNearestNode(&Coor_External[0], dist, pointID, rankID); - + if (rankID == rank) { - + /*--- Store the sensitivities at the matched local node. ---*/ - + for (iDim = 0; iDim < nDim; iDim++) Sensitivity[pointID*nDim+iDim] = Sens_External[iDim]; - + /*--- Keep track of how many points we match. ---*/ - + iPoint_Found++; - + /*--- Keep track of points with poor matches for reporting. ---*/ - + if (dist > 1e-10) unmatched++; - + } - + /*--- Increment counter for total points in the external file. ---*/ - + iPoint_Ext++; - + } } - + /*--- Close the external file. ---*/ - + external_file.close(); - + /*--- We have not received all nodes in the input file. Throw an error. ---*/ - + if ((iPoint_Ext < GetGlobal_nPointDomain()) && (rank == MASTER_NODE)) { sens_file.open(config->GetDV_Unordered_Sens_Filename().data(), ios::out); sens_file.close(); SU2_MPI::Error("Not enough points in the input sensitivity file.", CURRENT_FUNCTION); } - + /*--- Check for points with a poor match and report the count. ---*/ - + unsigned long myUnmatched = unmatched; unmatched = 0; SU2_MPI::Allreduce(&myUnmatched, &unmatched, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); @@ -14334,13 +10306,13 @@ void CPhysicalGeometry::ReadUnorderedSensitivity(CConfig *config) { cout << " Warning: there are " << unmatched; cout << " points with a match distance > 1e-10." << endl; } - + } - + } void CPhysicalGeometry::Check_Periodicity(CConfig *config) { - + /*--- Check for the presence of any periodic BCs and disable multigrid for now if found. ---*/ @@ -14349,54 +10321,55 @@ void CPhysicalGeometry::Check_Periodicity(CConfig *config) { cout << "WARNING: Periodicity has been detected. Disabling multigrid. "<< endl; config->SetMGLevels(0); } - + } -su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, jVertex, n, Trailing_Point, Leading_Point; su2double Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, zp1, zpn, MaxThickness_Value = 0, Thickness, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, MaxDistance, Distance, AoA; vector Xcoord, Ycoord, Zcoord, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; - + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } } - + AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; - + /*--- Translate to the origin ---*/ - + Xcoord_Trailing = Xcoord_Airfoil[0]; Ycoord_Trailing = Ycoord_Airfoil[0]; Zcoord_Trailing = Zcoord_Airfoil[0]; - + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); } - + /*--- Rotate the airfoil ---*/ - + ValCos = cos(AoA*PI_NUMBER/180.0); ValSin = sin(AoA*PI_NUMBER/180.0); - + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { XValue = Xcoord_Airfoil_[iVertex]; ZValue = Zcoord_Airfoil_[iVertex]; Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; } - + /*--- Identify upper and lower side, and store the value of the normal --*/ - + for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; @@ -14404,21 +10377,21 @@ su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; - + BiNormal[0] = Plane_Normal[0]; BiNormal[1] = Plane_Normal[1]; BiNormal[2] = Plane_Normal[2]; Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; - + Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; - + Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); - + unsigned short index = 2; - + /*--- Removing the trailing edge from list of points that we are going to use in the interpolation, to be sure that a blunt trailing edge do not affect the interpolation ---*/ @@ -14427,11 +10400,11 @@ su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double Ycoord.push_back(Ycoord_Airfoil_[iVertex]); Zcoord.push_back(Zcoord_Airfoil_[iVertex]); } - + } - + /*--- Order the arrays using the X component ---*/ - + for (iVertex = 0; iVertex < Xcoord.size(); iVertex++) { for (jVertex = 0; jVertex < Xcoord.size() - 1 - iVertex; jVertex++) { if (Xcoord[jVertex] > Xcoord[jVertex+1]) { @@ -14441,17 +10414,17 @@ su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double } } } - + n = Xcoord.size(); if (n > 1) { zp1 = (Zcoord[1]-Zcoord[0])/(Xcoord[1]-Xcoord[0]); zpn = (Zcoord[n-1]-Zcoord[n-2])/(Xcoord[n-1]-Xcoord[n-2]); Z2coord.resize(n+1); SetSpline(Xcoord, Zcoord, n, zp1, zpn, Z2coord); - + /*--- Compute the thickness (we add a fabs because we can not guarantee the right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/ - + MaxThickness_Value = 0.0; for (iVertex = 0; iVertex < Xcoord_Airfoil_.size(); iVertex++) { if (Zcoord_Normal[iVertex] < 0.0) { @@ -14463,7 +10436,7 @@ su2double CPhysicalGeometry::Compute_MaxThickness(su2double *Plane_P0, su2double else { MaxThickness_Value = 0.0; } return MaxThickness_Value; - + } su2double CPhysicalGeometry::Compute_Dihedral(su2double *LeadingEdge_im1, su2double *TrailingEdge_im1, @@ -14518,10 +10491,11 @@ su2double CPhysicalGeometry::Compute_Curvature(su2double *LeadingEdge_im1, su2do } -su2double CPhysicalGeometry::Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_Twist(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, Trailing_Point, Leading_Point; su2double MaxDistance, Distance, Twist = 0.0; - + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; @@ -14529,10 +10503,10 @@ su2double CPhysicalGeometry::Compute_Twist(su2double *Plane_P0, su2double *Plane Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } } - + Twist = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; return Twist; @@ -14560,11 +10534,11 @@ void CPhysicalGeometry::Compute_Wing_LeadingTrailing(su2double *LeadingEdge, su2 LeadingEdge[0] = Xcoord_Airfoil[Leading_Point]; LeadingEdge[1] = Ycoord_Airfoil[Leading_Point]; LeadingEdge[2] = Zcoord_Airfoil[Leading_Point]; - + TrailingEdge[0] = Xcoord_Airfoil[Trailing_Point]; TrailingEdge[1] = Ycoord_Airfoil[Trailing_Point]; TrailingEdge[2] = Zcoord_Airfoil[Trailing_Point]; - + } void CPhysicalGeometry::Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, su2double *TrailingEdge, su2double *Plane_P0, su2double *Plane_Normal, @@ -14595,28 +10569,30 @@ void CPhysicalGeometry::Compute_Fuselage_LeadingTrailing(su2double *LeadingEdge, } -su2double CPhysicalGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_Chord(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, Trailing_Point; su2double MaxDistance, Distance, Chord = 0.0; - + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ MaxDistance = 0.0; Trailing_Point = 0; for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - + if (MaxDistance < Distance) { MaxDistance = Distance; } } - + Chord = MaxDistance; - + return Chord; - + } -su2double CPhysicalGeometry::Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_Width(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, Trailing_Point; su2double MaxDistance, Distance, Width = 0.0; @@ -14632,7 +10608,8 @@ su2double CPhysicalGeometry::Compute_Width(su2double *Plane_P0, su2double *Plane } -su2double CPhysicalGeometry::Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_WaterLineWidth(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, + vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, Trailing_Point; su2double MinDistance, Distance, WaterLineWidth = 0.0; @@ -14651,7 +10628,8 @@ su2double CPhysicalGeometry::Compute_WaterLineWidth(su2double *Plane_P0, su2doub } -su2double CPhysicalGeometry::Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_Height(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, Trailing_Point; su2double MaxDistance, Distance, Height = 0.0; @@ -14668,114 +10646,120 @@ su2double CPhysicalGeometry::Compute_Height(su2double *Plane_P0, su2double *Plan } -su2double CPhysicalGeometry::Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { +su2double CPhysicalGeometry::Compute_LERadius(su2double *Plane_P0, su2double *Plane_Normal, vector &Xcoord_Airfoil, + vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex, Trailing_Point, Leading_Point; su2double MaxDistance, Distance, LERadius = 0.0, X1, X2, X3, Y1, Y2, Y3, Ma, Mb, Xc, Yc, Radius; - + /*--- Find the leading and trailing edges and compute the radius of curvature ---*/ - + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { - + Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } } - + X1 = Xcoord_Airfoil[Leading_Point-3]; Y1 = Zcoord_Airfoil[Leading_Point-3]; X2 = Xcoord_Airfoil[Leading_Point]; Y2 = Zcoord_Airfoil[Leading_Point]; - + X3 = Xcoord_Airfoil[Leading_Point+3]; Y3 = Zcoord_Airfoil[Leading_Point+3]; - + if (X2 != X1) Ma = (Y2-Y1) / (X2-X1); else Ma = 0.0; if (X3 != X2) Mb = (Y3-Y2) / (X3-X2); else Mb = 0.0; if (Mb != Ma) Xc = (Ma*Mb*(Y1-Y3)+Mb*(X1+X2)-Ma*(X2+X3))/(2.0*(Mb-Ma)); else Xc = 0.0; if (Ma != 0.0) Yc = -(1.0/Ma)*(Xc-0.5*(X1+X2))+0.5*(Y1+Y2); else Yc = 0.0; - + Radius = sqrt((Xc-X1)*(Xc-X1)+(Yc-Y1)*(Yc-Y1)); if (Radius != 0.0) LERadius = 1.0/Radius; else LERadius = 0.0; return LERadius; - + } -su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, su2double &ZLoc) { +su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *Plane_Normal, su2double Location, CConfig *config, + vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil, su2double &ZLoc) { unsigned long iVertex, jVertex, n_Upper, n_Lower, Trailing_Point, Leading_Point; - su2double Thickness_Location, Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Thickness_Value = 0.0, Length, Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, zp1, zpn, Chord, MaxDistance, Distance, AoA; - vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Z2coord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; + su2double Thickness_Location, Normal[3], Tangent[3], BiNormal[3], auxXCoord, auxYCoord, auxZCoord, Thickness_Value = 0.0, Length, + Xcoord_Trailing, Ycoord_Trailing, Zcoord_Trailing, ValCos, ValSin, XValue, ZValue, zp1, zpn, Chord, MaxDistance, Distance, AoA; + + vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Z2coord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord_Lower, + Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; + su2double Zcoord_Up, Zcoord_Down, ZLoc_, YLoc_; - + /*--- Find the leading and trailing edges and compute the angle of attack ---*/ - + MaxDistance = 0.0; Trailing_Point = 0; Leading_Point = 0; for (iVertex = 1; iVertex < Xcoord_Airfoil.size(); iVertex++) { Distance = sqrt(pow(Xcoord_Airfoil[iVertex] - Xcoord_Airfoil[Trailing_Point], 2.0) + pow(Ycoord_Airfoil[iVertex] - Ycoord_Airfoil[Trailing_Point], 2.0) + pow(Zcoord_Airfoil[iVertex] - Zcoord_Airfoil[Trailing_Point], 2.0)); - + if (MaxDistance < Distance) { MaxDistance = Distance; Leading_Point = iVertex; } } - + AoA = atan((Zcoord_Airfoil[Leading_Point] - Zcoord_Airfoil[Trailing_Point]) / (Xcoord_Airfoil[Trailing_Point] - Xcoord_Airfoil[Leading_Point]))*180/PI_NUMBER; Chord = MaxDistance; - + /*--- Translate to the origin ---*/ - + Xcoord_Trailing = Xcoord_Airfoil[0]; Ycoord_Trailing = Ycoord_Airfoil[0]; Zcoord_Trailing = Zcoord_Airfoil[0]; - + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { Xcoord_Airfoil_.push_back(Xcoord_Airfoil[iVertex] - Xcoord_Trailing); Ycoord_Airfoil_.push_back(Ycoord_Airfoil[iVertex] - Ycoord_Trailing); Zcoord_Airfoil_.push_back(Zcoord_Airfoil[iVertex] - Zcoord_Trailing); } - + /*--- Rotate the airfoil ---*/ - + ValCos = cos(AoA*PI_NUMBER/180.0); ValSin = sin(AoA*PI_NUMBER/180.0); - + for (iVertex = 0; iVertex < Xcoord_Airfoil.size(); iVertex++) { XValue = Xcoord_Airfoil_[iVertex]; ZValue = Zcoord_Airfoil_[iVertex]; - + Xcoord_Airfoil_[iVertex] = XValue*ValCos - ZValue*ValSin; Zcoord_Airfoil_[iVertex] = ZValue*ValCos + XValue*ValSin; } - + /*--- Identify upper and lower side, and store the value of the normal --*/ - + for (iVertex = 1; iVertex < Xcoord_Airfoil_.size(); iVertex++) { Tangent[0] = Xcoord_Airfoil_[iVertex] - Xcoord_Airfoil_[iVertex-1]; Tangent[1] = Ycoord_Airfoil_[iVertex] - Ycoord_Airfoil_[iVertex-1]; Tangent[2] = Zcoord_Airfoil_[iVertex] - Zcoord_Airfoil_[iVertex-1]; Length = sqrt(pow(Tangent[0], 2.0) + pow(Tangent[1], 2.0) + pow(Tangent[2], 2.0)); Tangent[0] /= Length; Tangent[1] /= Length; Tangent[2] /= Length; - + BiNormal[0] = Plane_Normal[0]; BiNormal[1] = Plane_Normal[1]; BiNormal[2] = Plane_Normal[2]; Length = sqrt(pow(BiNormal[0], 2.0) + pow(BiNormal[1], 2.0) + pow(BiNormal[2], 2.0)); BiNormal[0] /= Length; BiNormal[1] /= Length; BiNormal[2] /= Length; - + Normal[0] = Tangent[1]*BiNormal[2] - Tangent[2]*BiNormal[1]; Normal[1] = Tangent[2]*BiNormal[0] - Tangent[0]*BiNormal[2]; Normal[2] = Tangent[0]*BiNormal[1] - Tangent[1]*BiNormal[0]; - + Xcoord_Normal.push_back(Normal[0]); Ycoord_Normal.push_back(Normal[1]); Zcoord_Normal.push_back(Normal[2]); - + unsigned short index = 2; - + if (Normal[index] >= 0.0) { Xcoord_Upper.push_back(Xcoord_Airfoil_[iVertex]); Ycoord_Upper.push_back(Ycoord_Airfoil_[iVertex]); @@ -14786,11 +10770,11 @@ su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *P Ycoord_Lower.push_back(Ycoord_Airfoil_[iVertex]); Zcoord_Lower.push_back(Zcoord_Airfoil_[iVertex]); } - + } - + /*--- Order the arrays using the X component ---*/ - + for (iVertex = 0; iVertex < Xcoord_Upper.size(); iVertex++) { for (jVertex = 0; jVertex < Xcoord_Upper.size() - 1 - iVertex; jVertex++) { if (Xcoord_Upper[jVertex] > Xcoord_Upper[jVertex+1]) { @@ -14800,9 +10784,9 @@ su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *P } } } - + /*--- Order the arrays using the X component ---*/ - + for (iVertex = 0; iVertex < Xcoord_Lower.size(); iVertex++) { for (jVertex = 0; jVertex < Xcoord_Lower.size() - 1 - iVertex; jVertex++) { if (Xcoord_Lower[jVertex] > Xcoord_Lower[jVertex+1]) { @@ -14812,7 +10796,7 @@ su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *P } } } - + n_Upper = Xcoord_Upper.size(); if (n_Upper > 1) { zp1 = (Zcoord_Upper[1]-Zcoord_Upper[0])/(Xcoord_Upper[1]-Xcoord_Upper[0]); @@ -14820,7 +10804,7 @@ su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *P Z2coord_Upper.resize(n_Upper+1); SetSpline(Xcoord_Upper, Zcoord_Upper, n_Upper, zp1, zpn, Z2coord_Upper); } - + n_Lower = Xcoord_Lower.size(); if (n_Lower > 1) { zp1 = (Zcoord_Lower[1]-Zcoord_Lower[0])/(Xcoord_Lower[1]-Xcoord_Lower[0]); @@ -14828,43 +10812,44 @@ su2double CPhysicalGeometry::Compute_Thickness(su2double *Plane_P0, su2double *P Z2coord_Lower.resize(n_Lower+1); SetSpline(Xcoord_Lower, Zcoord_Lower, n_Lower, zp1, zpn, Z2coord_Lower); } - + if ((n_Upper > 1) && (n_Lower > 1)) { - + Thickness_Location = - Chord*(1.0-Location); - + Zcoord_Up = GetSpline(Xcoord_Upper, Zcoord_Upper, Z2coord_Upper, n_Upper, Thickness_Location); Zcoord_Down = GetSpline(Xcoord_Lower, Zcoord_Lower, Z2coord_Lower, n_Lower, Thickness_Location); - + YLoc_ = Thickness_Location; ZLoc_ = 0.5*(Zcoord_Up + Zcoord_Down); - + ZLoc = sin(-AoA*PI_NUMBER/180.0)*YLoc_ + cos(-AoA*PI_NUMBER/180.0)*ZLoc_ + Zcoord_Trailing; - + /*--- Compute the thickness (we add a fabs because we can not guarantee the right sorting of the points and the upper and/or lower part of the airfoil is not well defined) ---*/ - + Thickness_Value = fabs(Zcoord_Up - Zcoord_Down); - + } else { Thickness_Value = 0.0; } return Thickness_Value; - + } su2double CPhysicalGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, vector &Xcoord_Airfoil, vector &Ycoord_Airfoil, vector &Zcoord_Airfoil) { unsigned long iVertex; su2double Area_Value = 0.0; - vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord, Xcoord_Normal, Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; + vector Xcoord_Upper, Ycoord_Upper, Zcoord_Upper, Xcoord_Lower, Ycoord_Lower, Zcoord_Lower, Z2coord, Xcoord_Normal, + Ycoord_Normal, Zcoord_Normal, Xcoord_Airfoil_, Ycoord_Airfoil_, Zcoord_Airfoil_; su2double DeltaZ, DeltaX, X, Z; - + /*--- Use the Green theorem to evaluate the area (the points have been sortered), we assume that the airfoil is in the X-Z plane ---*/ - + Area_Value = 0.0; - + for (iVertex = 0; iVertex < Xcoord_Airfoil.size()-1; iVertex++) { X = 0.5*(Xcoord_Airfoil[iVertex]+Xcoord_Airfoil[iVertex+1]); Z = 0.5*(Zcoord_Airfoil[iVertex]+Zcoord_Airfoil[iVertex+1]); @@ -14872,17 +10857,17 @@ su2double CPhysicalGeometry::Compute_Area(su2double *Plane_P0, su2double *Plane_ DeltaZ = Zcoord_Airfoil[iVertex+1] - Zcoord_Airfoil[iVertex]; Area_Value += 0.5*( X*DeltaZ-Z*DeltaX); } - + X = 0.5*(Xcoord_Airfoil[Xcoord_Airfoil.size()-1]+Xcoord_Airfoil[0]); Z = 0.5*(Zcoord_Airfoil[Xcoord_Airfoil.size()-1]+Zcoord_Airfoil[0]); DeltaX = Xcoord_Airfoil[0] - Xcoord_Airfoil[Xcoord_Airfoil.size()-1]; DeltaZ = Zcoord_Airfoil[0] - Zcoord_Airfoil[Xcoord_Airfoil.size()-1]; Area_Value += 0.5 * (X*DeltaZ-Z*DeltaX); - + Area_Value = fabs(Area_Value); - + return Area_Value; - + } su2double CPhysicalGeometry::Compute_Length(su2double *Plane_P0, su2double *Plane_Normal, CConfig *config, @@ -14926,14 +10911,14 @@ void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface, su2double MinPlane, MaxPlane, dPlane, *Area, *MaxThickness, *ToC, *Chord, *LERadius, *Twist, *Curvature, *Dihedral, SemiSpan; vector *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil; ofstream Wing_File, Section_File; - + /*--- Make a large number of section cuts for approximating volume ---*/ - + nPlane = config->GetnWingStations(); SemiSpan = config->GetSemiSpan(); - + /*--- Allocate memory for the section cutting ---*/ - + Area = new su2double [nPlane]; MaxThickness = new su2double [nPlane]; Chord = new su2double [nPlane]; @@ -14946,7 +10931,7 @@ void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface, su2double **LeadingEdge = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) LeadingEdge[iPlane] = new su2double[nDim]; - + su2double **TrailingEdge = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) TrailingEdge[iPlane] = new su2double[nDim]; @@ -14954,11 +10939,11 @@ void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface, su2double **Plane_P0 = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) Plane_P0[iPlane] = new su2double[nDim]; - + su2double **Plane_Normal = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) Plane_Normal[iPlane] = new su2double[nDim]; - + MinPlane = config->GetStations_Bounds(0); MaxPlane = config->GetStations_Bounds(1); dPlane = fabs((MaxPlane - MinPlane)/su2double(nPlane-1)); @@ -14976,16 +10961,16 @@ void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface, Plane_Normal[iPlane][2] = 1.0; Plane_P0[iPlane][2] = MinPlane + iPlane*dPlane; } - + } - + /*--- Allocate some vectors for storing airfoil coordinates ---*/ - + Xcoord_Airfoil = new vector[nPlane]; Ycoord_Airfoil = new vector[nPlane]; Zcoord_Airfoil = new vector[nPlane]; Variable_Airfoil = new vector[nPlane]; - + /*--- Create the section slices through the geometry ---*/ for (iPlane = 0; iPlane < nPlane; iPlane++) { @@ -14998,9 +10983,9 @@ void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface, } /*--- Compute airfoil characteristic only in the master node ---*/ - + if (rank == MASTER_NODE) { - + /*--- Write an output file---*/ if (config->GetTabular_FileFormat() == TAB_CSV) { @@ -15204,11 +11189,11 @@ void CPhysicalGeometry::Compute_Wing(CConfig *config, bool original_surface, for (iPlane = 0; iPlane < nPlane; iPlane++) delete [] Plane_P0[iPlane]; delete [] Plane_P0; - + for (iPlane = 0; iPlane < nPlane; iPlane++) delete [] Plane_Normal[iPlane]; delete [] Plane_Normal; - + delete [] Area; delete [] MaxThickness; delete [] Chord; @@ -15507,108 +11492,108 @@ void CPhysicalGeometry::Compute_Nacelle(CConfig *config, bool original_surface, su2double Angle, MinAngle, MaxAngle, dAngle, *Area, *MaxThickness, *ToC, *Chord, *LERadius, *Twist; vector *Xcoord_Airfoil, *Ycoord_Airfoil, *Zcoord_Airfoil, *Variable_Airfoil; ofstream Nacelle_File, Section_File; - - + + /*--- Make a large number of section cuts for approximating volume ---*/ - + nPlane = config->GetnWingStations(); - + /*--- Allocate memory for the section cutting ---*/ - + Area = new su2double [nPlane]; MaxThickness = new su2double [nPlane]; Chord = new su2double [nPlane]; LERadius = new su2double [nPlane]; ToC = new su2double [nPlane]; Twist = new su2double [nPlane]; - + su2double **LeadingEdge = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) LeadingEdge[iPlane] = new su2double[nDim]; - + su2double **TrailingEdge = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) TrailingEdge[iPlane] = new su2double[nDim]; - + su2double **Plane_P0 = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) Plane_P0[iPlane] = new su2double[nDim]; - + su2double **Plane_Normal = new su2double*[nPlane]; for (iPlane = 0; iPlane < nPlane; iPlane++ ) Plane_Normal[iPlane] = new su2double[nDim]; - + MinAngle = config->GetStations_Bounds(0); MaxAngle = config->GetStations_Bounds(1); dAngle = fabs((MaxAngle - MinAngle)/su2double(nPlane-1)); - + for (iPlane = 0; iPlane < nPlane; iPlane++) { Plane_Normal[iPlane][0] = 0.0; Plane_P0[iPlane][0] = 0.0; Plane_Normal[iPlane][1] = 0.0; Plane_P0[iPlane][1] = 0.0; Plane_Normal[iPlane][2] = 0.0; Plane_P0[iPlane][2] = 0.0; - + /*--- Apply roll to cut the nacelle ---*/ Angle = MinAngle + iPlane*dAngle*PI_NUMBER/180.0; - + if (Angle <= 0) Angle = 1E-6; if (Angle >= 360) Angle = 359.999999; Plane_Normal[iPlane][0] = 0.0; Plane_Normal[iPlane][1] = -sin(Angle); Plane_Normal[iPlane][2] = cos(Angle); - + /*--- Apply tilt angle to the plane ---*/ - + su2double Tilt_Angle = config->GetNacelleLocation(3)*PI_NUMBER/180; su2double Plane_NormalX_Tilt = Plane_Normal[iPlane][0]*cos(Tilt_Angle) + Plane_Normal[iPlane][2]*sin(Tilt_Angle); su2double Plane_NormalY_Tilt = Plane_Normal[iPlane][1]; su2double Plane_NormalZ_Tilt = Plane_Normal[iPlane][2]*cos(Tilt_Angle) - Plane_Normal[iPlane][0]*sin(Tilt_Angle); - + /*--- Apply toe angle to the plane ---*/ - + su2double Toe_Angle = config->GetNacelleLocation(4)*PI_NUMBER/180; su2double Plane_NormalX_Tilt_Toe = Plane_NormalX_Tilt*cos(Toe_Angle) - Plane_NormalY_Tilt*sin(Toe_Angle); su2double Plane_NormalY_Tilt_Toe = Plane_NormalX_Tilt*sin(Toe_Angle) + Plane_NormalY_Tilt*cos(Toe_Angle); su2double Plane_NormalZ_Tilt_Toe = Plane_NormalZ_Tilt; - + /*--- Update normal vector ---*/ - + Plane_Normal[iPlane][0] = Plane_NormalX_Tilt_Toe; Plane_Normal[iPlane][1] = Plane_NormalY_Tilt_Toe; Plane_Normal[iPlane][2] = Plane_NormalZ_Tilt_Toe; - + /*--- Point in the plane ---*/ - + Plane_P0[iPlane][0] = config->GetNacelleLocation(0); Plane_P0[iPlane][1] = config->GetNacelleLocation(1); Plane_P0[iPlane][2] = config->GetNacelleLocation(2); - + } - + /*--- Allocate some vectors for storing airfoil coordinates ---*/ - + Xcoord_Airfoil = new vector[nPlane]; Ycoord_Airfoil = new vector[nPlane]; Zcoord_Airfoil = new vector[nPlane]; Variable_Airfoil = new vector[nPlane]; - + /*--- Create the section slices through the geometry ---*/ - + for (iPlane = 0; iPlane < nPlane; iPlane++) { - + ComputeAirfoil_Section(Plane_P0[iPlane], Plane_Normal[iPlane], -1E6, 1E6, -1E6, 1E6, -1E6, 1E6, NULL, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane], Variable_Airfoil[iPlane], original_surface, config); - + } - + /*--- Compute airfoil characteristic only in the master node ---*/ - + if (rank == MASTER_NODE) { - + /*--- Write an output file---*/ - + if (config->GetTabular_FileFormat() == TAB_CSV) { Nacelle_File.open("nacelle_description.csv", ios::out); if (config->GetSystemMeasurements() == US) @@ -15625,1899 +11610,176 @@ void CPhysicalGeometry::Compute_Nacelle(CConfig *config, bool original_surface, Nacelle_File << "VARIABLES = \"q (deg)\",\"Area (m2)\",\"Max. Thickness (m)\",\"Chord (m)\",\"Leading Edge Radius (1/m)\",\"Max. Thickness/Chord\",\"Twist (deg)\",\"Leading Edge XLoc\",\"Leading Edge ZLoc\",\"Trailing Edge XLoc\",\"Trailing Edge ZLoc\"" << endl; Nacelle_File << "ZONE T= \"Baseline nacelle\"" << endl; } - - + + /*--- Evaluate geometrical quatities that do not require any kind of filter, local to each point ---*/ - + for (iPlane = 0; iPlane < nPlane; iPlane++) { - + for (iDim = 0; iDim < nDim; iDim++) { LeadingEdge[iPlane][iDim] = 0.0; TrailingEdge[iPlane][iDim] = 0.0; } - + Area[iPlane] = 0.0; MaxThickness[iPlane] = 0.0; Chord[iPlane] = 0.0; LERadius[iPlane] = 0.0; ToC[iPlane] = 0.0; Twist[iPlane] = 0.0; - - if (Xcoord_Airfoil[iPlane].size() > 1) { - - Compute_Wing_LeadingTrailing(LeadingEdge[iPlane], TrailingEdge[iPlane], Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - - Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - - MaxThickness[iPlane] = Compute_MaxThickness(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - - Chord[iPlane] = Compute_Chord(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - - Twist[iPlane] = Compute_Twist(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - - LERadius[iPlane] = Compute_LERadius(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - - ToC[iPlane] = MaxThickness[iPlane] / Chord[iPlane]; - - - } - - } - - /*--- Plot the geometrical quatities ---*/ - - for (iPlane = 0; iPlane < nPlane; iPlane++) { - - su2double theta_deg = atan2(Plane_Normal[iPlane][1], -Plane_Normal[iPlane][2])/PI_NUMBER*180 + 180; - - if (Xcoord_Airfoil[iPlane].size() > 1) { - if (config->GetTabular_FileFormat() == TAB_CSV) { - Nacelle_File << theta_deg <<", "<< Area[iPlane] <<", "<< MaxThickness[iPlane] <<", "<< Chord[iPlane] <<", "<< LERadius[iPlane] <<", "<< ToC[iPlane] - <<", "<< Twist[iPlane] <<", "<< LeadingEdge[iPlane][0] <<", "<< LeadingEdge[iPlane][2] - <<", "<< TrailingEdge[iPlane][0] <<", "<< TrailingEdge[iPlane][2] << endl; - } - else { - Nacelle_File << theta_deg <<" "<< Area[iPlane] <<" "<< MaxThickness[iPlane] <<" "<< Chord[iPlane] <<" "<< LERadius[iPlane] <<" "<< ToC[iPlane] - <<" "<< Twist[iPlane] <<" "<< LeadingEdge[iPlane][0] <<" "<< LeadingEdge[iPlane][2] - <<" "<< TrailingEdge[iPlane][0] <<" "<< TrailingEdge[iPlane][2] << endl; - - } - } - - } - - Nacelle_File.close(); - - Section_File.open("nacelle_slices.dat", ios::out); - - for (iPlane = 0; iPlane < nPlane; iPlane++) { - - if (iPlane == 0) { - Section_File << "TITLE = \"Nacelle Slices\"" << endl; - if (config->GetSystemMeasurements() == US) - Section_File << "VARIABLES = \"x (in)\", \"y (in)\", \"z (in)\", \"x2D/c\", \"y2D/c\"" << endl; - else Section_File << "VARIABLES = \"x (m)\", \"y (m)\", \"z (m)\", \"x2D/c\", \"y2D/c\"" << endl; - } - - if (Xcoord_Airfoil[iPlane].size() > 1) { - - su2double theta_deg = atan2(Plane_Normal[iPlane][1], -Plane_Normal[iPlane][2])/PI_NUMBER*180 + 180; - su2double Angle = theta_deg*PI_NUMBER/180 - 0.5*PI_NUMBER; - - Section_File << "ZONE T=\"q = " << theta_deg << " deg\", I= " << Xcoord_Airfoil[iPlane].size() << ", F=POINT" << endl; - - for (iVertex = 0; iVertex < Xcoord_Airfoil[iPlane].size(); iVertex++) { - - /*--- Move to the origin ---*/ - - su2double XValue_ = Xcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][0]; - su2double ZValue_ = Zcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][2]; - - /*--- Rotate the airfoil and divide by the chord ---*/ - - su2double ValCos = cos(Twist[iPlane]*PI_NUMBER/180.0); - su2double ValSin = sin(Twist[iPlane]*PI_NUMBER/180.0); - - su2double XValue = (XValue_*ValCos - ZValue_*ValSin) / Chord[iPlane]; - su2double ZValue = (ZValue_*ValCos + XValue_*ValSin) / Chord[iPlane]; - - su2double XCoord = Xcoord_Airfoil[iPlane][iVertex] + config->GetNacelleLocation(0); - su2double YCoord = (Ycoord_Airfoil[iPlane][iVertex]*cos(Angle) - Zcoord_Airfoil[iPlane][iVertex]*sin(Angle)) + config->GetNacelleLocation(1); - su2double ZCoord = (Zcoord_Airfoil[iPlane][iVertex]*cos(Angle) + Ycoord_Airfoil[iPlane][iVertex]*sin(Angle)) + config->GetNacelleLocation(2); - /*--- Write the file ---*/ - - Section_File << XCoord << " " << YCoord << " " << ZCoord << " " << XValue << " " << ZValue << endl; - } - } - - } - - Section_File.close(); - - - /*--- Compute the wing volume using a composite Simpson's rule ---*/ - - Nacelle_Volume = 0.0; - for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) { if (Xcoord_Airfoil[iPlane].size() > 1) { - Nacelle_Volume += (1.0/3.0)*dAngle*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]); - } - } - - /*--- Evaluate Max and Min quantities ---*/ - - Nacelle_MaxMaxThickness = -1E6; Nacelle_MinMaxThickness = 1E6; Nacelle_MinChord = 1E6; Nacelle_MaxChord = -1E6; - Nacelle_MinLERadius = 1E6; Nacelle_MaxLERadius = -1E6; Nacelle_MinToC = 1E6; Nacelle_MaxToC = -1E6; - Nacelle_MaxTwist = -1E6; - - for (iPlane = 0; iPlane < nPlane; iPlane++) { - if (MaxThickness[iPlane] != 0.0) Nacelle_MinMaxThickness = min(Nacelle_MinMaxThickness, MaxThickness[iPlane]); - Nacelle_MaxMaxThickness = max(Nacelle_MaxMaxThickness, MaxThickness[iPlane]); - if (Chord[iPlane] != 0.0) Nacelle_MinChord = min(Nacelle_MinChord, Chord[iPlane]); - Nacelle_MaxChord = max(Nacelle_MaxChord, Chord[iPlane]); - if (LERadius[iPlane] != 0.0) Nacelle_MinLERadius = min(Nacelle_MinLERadius, LERadius[iPlane]); - Nacelle_MaxLERadius = max(Nacelle_MaxLERadius, LERadius[iPlane]); - if (ToC[iPlane] != 0.0) Nacelle_MinToC = min(Nacelle_MinToC, ToC[iPlane]); - Nacelle_MaxToC = max(Nacelle_MaxToC, ToC[iPlane]); - Nacelle_ObjFun_MinToC = sqrt((Nacelle_MinToC - 0.07)*(Nacelle_MinToC - 0.07)); - Nacelle_MaxTwist = max(Nacelle_MaxTwist, fabs(Twist[iPlane])); - } - - } - - /*--- Free memory for the section cuts ---*/ - - delete [] Xcoord_Airfoil; - delete [] Ycoord_Airfoil; - delete [] Zcoord_Airfoil; - delete [] Variable_Airfoil; - - for (iPlane = 0; iPlane < nPlane; iPlane++) - delete [] LeadingEdge[iPlane]; - delete [] LeadingEdge; - - for (iPlane = 0; iPlane < nPlane; iPlane++) - delete [] TrailingEdge[iPlane]; - delete [] TrailingEdge; - - for (iPlane = 0; iPlane < nPlane; iPlane++) - delete [] Plane_P0[iPlane]; - delete [] Plane_P0; - - for (iPlane = 0; iPlane < nPlane; iPlane++) - delete [] Plane_Normal[iPlane]; - delete [] Plane_Normal; - - delete [] Area; - delete [] MaxThickness; - delete [] Chord; - delete [] LERadius; - delete [] ToC; - delete [] Twist; - -} - -CMultiGridGeometry::CMultiGridGeometry(CGeometry **geometry, CConfig *config_container, unsigned short iMesh) : CGeometry() { - - /*--- CGeometry & CConfig pointers to the fine grid level for clarity. We may - need access to the other zones in the mesh for zone boundaries. ---*/ - - CGeometry *fine_grid = geometry[iMesh-1]; - CConfig *config = config_container; - - /*--- Local variables ---*/ - - unsigned long iPoint, Index_CoarseCV, CVPoint, iElem, iVertex, jPoint, iteration, nVertexS, nVertexR, nBufferS_Vector, nBufferR_Vector, iParent, jVertex, *Buffer_Receive_Parent = NULL, *Buffer_Send_Parent = NULL, *Buffer_Receive_Children = NULL, *Buffer_Send_Children = NULL, *Parent_Remote = NULL, *Children_Remote = NULL, *Parent_Local = NULL, *Children_Local = NULL, Local_nPointCoarse, Local_nPointFine, Global_nPointCoarse, Global_nPointFine;; - short marker_seed; - bool agglomerate_seed = true; - unsigned short nChildren, iNode, counter, iMarker, jMarker, priority, MarkerS, MarkerR, *nChildren_MPI; - vector Suitable_Indirect_Neighbors, Aux_Parent; - vector::iterator it; - - unsigned short nMarker_Max = config->GetnMarker_Max(); - - unsigned short *copy_marker = new unsigned short [nMarker_Max]; - -#ifdef HAVE_MPI - int send_to, receive_from; - SU2_MPI::Status status; -#endif - - nDim = fine_grid->GetnDim(); // Write the number of dimensions of the coarse grid. - - /*--- Create a queue system to deo the agglomeration - 1st) More than two markers ---> Vertices (never agglomerate) - 2nd) Two markers ---> Edges (agglomerate if same BC, never agglomerate if different BC) - 3rd) One marker ---> Surface (always agglomarate) - 4th) No marker ---> Internal Volume (always agglomarate) ---*/ - - /*--- Set a marker to indicate indirect agglomeration ---*/ - - if (iMesh == MESH_1) { - - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) - fine_grid->node[iPoint]->SetAgglomerate_Indirect(false); - - for (iElem = 0; iElem < fine_grid->GetnElem(); iElem++) { - if ((fine_grid->elem[iElem]->GetVTK_Type() == HEXAHEDRON) || - (fine_grid->elem[iElem]->GetVTK_Type() == QUADRILATERAL)) { - for (iNode = 0; iNode < fine_grid->elem[iElem]->GetnNodes(); iNode++) { - iPoint = fine_grid->elem[iElem]->GetNode(iNode); - fine_grid->node[iPoint]->SetAgglomerate_Indirect(true); - } - } - } - - } - - /*--- Create the coarse grid structure using as baseline the fine grid ---*/ - - CMultiGridQueue MGQueue_InnerCV(fine_grid->GetnPoint()); - - nPointNode = fine_grid->GetnPoint(); - node = new CPoint*[fine_grid->GetnPoint()]; - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { - - /*--- Create node structure ---*/ - - node[iPoint] = new CPoint(nDim, iPoint, config); - - /*--- Set the indirect agglomeration to false ---*/ - - node[iPoint]->SetAgglomerate_Indirect(false); - } - - Index_CoarseCV = 0; - - /*--- The first step is the boundary agglomeration. ---*/ - - for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) { - - for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { - iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); - - /*--- If the element has not being previously agglomerated and it belongs - to the physical domain, then the agglomeration is studied ---*/ - - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && - (fine_grid->node[iPoint]->GetDomain()) && - (GeometricalCheck(iPoint, fine_grid, config))) { - - nChildren = 1; - - /*--- We set an index for the parent control volume ---*/ - - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We add the seed point (child) to the parent control volume ---*/ - - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - agglomerate_seed = true; counter = 0; marker_seed = iMarker; - - /*--- For a particular point in the fine grid we save all the markers - that are in that point ---*/ - - for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) - if (fine_grid->node[iPoint]->GetVertex(jMarker) != -1) { - copy_marker[counter] = jMarker; - counter++; - } - - /*--- To aglomerate a vertex it must have only one physical bc!! - This can be improved. If there is only a marker, it is a good - candidate for agglomeration ---*/ - - if (counter == 1) agglomerate_seed = true; - - /*--- If there are two markers, we will aglomerate if one of the - marker is SEND_RECEIVE ---*/ - - if (counter == 2) { - if ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) || - (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) agglomerate_seed = true; - else agglomerate_seed = false; - } - - /*--- If there are more than 2 markers, the aglomeration will be discarted ---*/ - - if (counter > 2) agglomerate_seed = false; - - /*--- If the seed can be agglomerated, we try to agglomerate more points ---*/ - - if (agglomerate_seed) { - - /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ - - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - - CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); - - /*--- The new point can be agglomerated ---*/ - - if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - } - - } - - Suitable_Indirect_Neighbors.clear(); - - if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) - SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); - - /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ - - for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { - - CVPoint = Suitable_Indirect_Neighbors[iNode]; - - /*--- The new point can be agglomerated ---*/ - - if (SetBoundAgglomeration(CVPoint, marker_seed, fine_grid, config)) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the indirect agglomeration information ---*/ - - if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) - node[Index_CoarseCV]->SetAgglomerate_Indirect(true); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - } - } - - - } - - /*--- Update the number of child of the control volume ---*/ - - node[Index_CoarseCV]->SetnChildren_CV(nChildren); - Index_CoarseCV++; - } - } - } - - /*--- Agglomerate all the nodes that have more than one physical boundary condition, - Maybe here we can add the posibility of merging the vertex that have the same number, - and kind of markers---*/ - - for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker++) - for (iVertex = 0; iVertex < fine_grid->GetnVertex(iMarker); iVertex++) { - iPoint = fine_grid->vertex[iMarker][iVertex]->GetNode(); - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && - (fine_grid->node[iPoint]->GetDomain())) { - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - node[Index_CoarseCV]->SetnChildren_CV(1); - Index_CoarseCV++; - } - } - - /*--- Update the queue with the results from the boundary agglomeration ---*/ - - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { - - /*--- The CV has been agglomerated, remove form the list ---*/ - - if (fine_grid->node[iPoint]->GetAgglomerate() == true) { - - MGQueue_InnerCV.RemoveCV(iPoint); - - } - - else { - - /*--- Count the number of agglomerated neighbors, and modify the queue ---*/ - - priority = 0; - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - if (fine_grid->node[jPoint]->GetAgglomerate() == true) priority++; - } - MGQueue_InnerCV.MoveCV(iPoint, priority); - } - } - - /*--- Agglomerate the domain nodes ---*/ - - iteration = 0; - while (!MGQueue_InnerCV.EmptyQueue() && (iteration < fine_grid->GetnPoint())) { - - iPoint = MGQueue_InnerCV.NextCV(); - iteration ++; - - /*--- If the element has not being previously agglomerated, belongs to the physical domain, - and satisfies several geometrical criteria then the seed CV is acepted for agglomeration ---*/ - - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && - (fine_grid->node[iPoint]->GetDomain()) && - (GeometricalCheck(iPoint, fine_grid, config))) { - - nChildren = 1; - - /*--- We set an index for the parent control volume ---*/ - - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We add the seed point (child) to the parent control volume ---*/ - - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - - /*--- Update the queue with the seed point (remove the seed and - increase the priority of the neighbors) ---*/ - - MGQueue_InnerCV.Update(iPoint, fine_grid); - - /*--- Now we do a sweep over all the nodes that surround the seed point ---*/ - - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - - CVPoint = fine_grid->node[iPoint]->GetPoint(iNode); - - /*--- Determine if the CVPoint can be agglomerated ---*/ - - if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && - (fine_grid->node[CVPoint]->GetDomain()) && - (GeometricalCheck(CVPoint, fine_grid, config))) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - - /*--- Update the queue with the new control volume (remove the CV and - increase the priority of the neighbors) ---*/ - - MGQueue_InnerCV.Update(CVPoint, fine_grid); - - } - - } - - /*--- Subrotuine to identify the indirect neighbors ---*/ - - Suitable_Indirect_Neighbors.clear(); - if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) - SetSuitableNeighbors(&Suitable_Indirect_Neighbors, iPoint, Index_CoarseCV, fine_grid); - - /*--- Now we do a sweep over all the indirect nodes that can be added ---*/ - - for (iNode = 0; iNode < Suitable_Indirect_Neighbors.size(); iNode ++) { - - CVPoint = Suitable_Indirect_Neighbors[iNode]; - - /*--- The new point can be agglomerated ---*/ - - if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && - (fine_grid->node[CVPoint]->GetDomain())) { - - /*--- We set the value of the parent ---*/ - - fine_grid->node[CVPoint]->SetParent_CV(Index_CoarseCV); - - /*--- We set the indirect agglomeration information ---*/ - - if (fine_grid->node[CVPoint]->GetAgglomerate_Indirect()) - node[Index_CoarseCV]->SetAgglomerate_Indirect(true); - - /*--- We set the value of the child ---*/ - - node[Index_CoarseCV]->SetChildren_CV(nChildren, CVPoint); - nChildren++; - - /*--- Update the queue with the new control volume (remove the CV and - increase the priority of the neighbors) ---*/ - - MGQueue_InnerCV.Update(CVPoint, fine_grid); - - } - } - - /*--- Update the number of control of childrens ---*/ - - node[Index_CoarseCV]->SetnChildren_CV(nChildren); - Index_CoarseCV++; - } - else { - - /*--- The seed point can not be agglomerated because of size, domain, streching, etc. - move the point to the lowest priority ---*/ - - MGQueue_InnerCV.MoveCV(iPoint, -1); - } - - } - - /*--- Add all the elements that have not being agglomerated, in the previous stage ---*/ - - for (iPoint = 0; iPoint < fine_grid->GetnPoint(); iPoint ++) { - if ((fine_grid->node[iPoint]->GetAgglomerate() == false) && (fine_grid->node[iPoint]->GetDomain())) { - - nChildren = 1; - fine_grid->node[iPoint]->SetParent_CV(Index_CoarseCV); - if (fine_grid->node[iPoint]->GetAgglomerate_Indirect()) - node[Index_CoarseCV]->SetAgglomerate_Indirect(true); - node[Index_CoarseCV]->SetChildren_CV(0, iPoint); - node[Index_CoarseCV]->SetnChildren_CV(nChildren); - Index_CoarseCV++; - - } - } - - nPointDomain = Index_CoarseCV; - - /*--- Check that there are no hanging nodes ---*/ - - unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iCoarsePoint_Complete; - unsigned short iChildren; - - /*--- Find the point surrounding a point ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { - iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); - iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); - if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); - } - } - } - - /*--- Detect isolated points and merge them with its correct neighbor ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { - - if (node[iCoarsePoint]->GetnPoint() == 1) { - - /*--- Find the neighbor of the isolated point. This neighbor is the right control volume ---*/ - - iCoarsePoint_Complete = node[iCoarsePoint]->GetPoint(0); - - /*--- Add the children to the connected control volume (and modify it parent indexing). - Identify the child CV from the finest grid and added to the correct control volume. - Set the parent CV of iFinePoint. Instead of using the original - (iCoarsePoint) one use the new one (iCoarsePoint_Complete) ---*/ - - nChildren = node[iCoarsePoint_Complete]->GetnChildren_CV(); - - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - node[iCoarsePoint_Complete]->SetChildren_CV(nChildren, iFinePoint); - nChildren++; - fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint_Complete); - } - - /*--- Update the number of children control volumes ---*/ - - node[iCoarsePoint_Complete]->SetnChildren_CV(nChildren); - node[iCoarsePoint]->SetnChildren_CV(0); - - } - } - - // unsigned long iPointFree = nPointDomain-1; - // iCoarsePoint = 0; - // - // do { - // - // if (node[iCoarsePoint]->GetnChildren_CV() == 0) { - // - // while (node[iPointFree]->GetnChildren_CV() == 0) { - // Index_CoarseCV--; - // iPointFree--; - // } - // - // nChildren = node[iPointFree]->GetnChildren_CV(); - // for (iChildren = 0; iChildren < nChildren; iChildren ++) { - // iFinePoint = node[iPointFree]->GetChildren_CV(iChildren); - // node[iCoarsePoint]->SetChildren_CV(iChildren, iFinePoint); - // fine_grid->node[iFinePoint]->SetParent_CV(iCoarsePoint); - // } - // node[iCoarsePoint]->SetnChildren_CV(nChildren); - // node[iPointFree]->SetnChildren_CV(0); - // - // Index_CoarseCV--; - // iPointFree--; - // - // } - // - // iCoarsePoint++; - // - // } while ((iCoarsePoint-1) < Index_CoarseCV); - // - // nPointDomain = Index_CoarseCV; - - /*--- Reset the point surrounding a point ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPointDomain; iCoarsePoint ++) { - node[iCoarsePoint]->ResetPoint(); - } - - /*--- Dealing with MPI parallelization, the objective is that the received nodes must be agglomerated - in the same way as the donor nodes. Send the node agglomeration information of the donor - (parent and children), Sending only occurs with MPI ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if ((config->GetMarker_All_KindBC(iMarker) == SEND_RECEIVE) && - (config->GetMarker_All_SendRecv(iMarker) > 0)) { - - MarkerS = iMarker; MarkerR = iMarker+1; - -#ifdef HAVE_MPI - send_to = config->GetMarker_All_SendRecv(MarkerS)-1; - receive_from = abs(config->GetMarker_All_SendRecv(MarkerR))-1; -#endif - - nVertexS = fine_grid->nVertex[MarkerS]; nVertexR = fine_grid->nVertex[MarkerR]; - nBufferS_Vector = nVertexS; nBufferR_Vector = nVertexR; - - /*--- Allocate Receive and send buffers ---*/ - - Buffer_Receive_Children = new unsigned long [nBufferR_Vector]; - Buffer_Send_Children = new unsigned long [nBufferS_Vector]; - - Buffer_Receive_Parent = new unsigned long [nBufferR_Vector]; - Buffer_Send_Parent = new unsigned long [nBufferS_Vector]; - - /*--- Copy the information that should be sended ---*/ - - for (iVertex = 0; iVertex < nVertexS; iVertex++) { - iPoint = fine_grid->vertex[MarkerS][iVertex]->GetNode(); - Buffer_Send_Children[iVertex] = iPoint; - Buffer_Send_Parent[iVertex] = fine_grid->node[iPoint]->GetParent_CV(); - } - -#ifdef HAVE_MPI - /*--- Send/Receive information using Sendrecv ---*/ - SU2_MPI::Sendrecv(Buffer_Send_Children, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,0, - Buffer_Receive_Children, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,0, MPI_COMM_WORLD, &status); - SU2_MPI::Sendrecv(Buffer_Send_Parent, nBufferS_Vector, MPI_UNSIGNED_LONG, send_to,1, - Buffer_Receive_Parent, nBufferR_Vector, MPI_UNSIGNED_LONG, receive_from,1, MPI_COMM_WORLD, &status); -#else - /*--- Receive information without MPI ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - Buffer_Receive_Children[iVertex] = Buffer_Send_Children[iVertex]; - Buffer_Receive_Parent[iVertex] = Buffer_Send_Parent[iVertex]; - } -#endif - - /*--- Deallocate send buffer ---*/ - - delete [] Buffer_Send_Children; - delete [] Buffer_Send_Parent; - - /*--- Create a list of the parent nodes without repeated parents ---*/ - - Aux_Parent.clear(); - for (iVertex = 0; iVertex < nVertexR; iVertex++) - Aux_Parent.push_back (Buffer_Receive_Parent[iVertex]); - - sort(Aux_Parent.begin(), Aux_Parent.end()); - it = unique(Aux_Parent.begin(), Aux_Parent.end()); - Aux_Parent.resize(it - Aux_Parent.begin()); - - /*--- Allocate some structures ---*/ - - Parent_Remote = new unsigned long[nVertexR]; - Children_Remote = new unsigned long[nVertexR]; - Parent_Local = new unsigned long[nVertexR]; - Children_Local = new unsigned long[nVertexR]; - - /*--- Create the local vector and remote for the parents and the children ---*/ - - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - Parent_Remote[iVertex] = Buffer_Receive_Parent[iVertex]; - - /*--- We use the same sorting as in the donor domain ---*/ - - for (jVertex = 0; jVertex < Aux_Parent.size(); jVertex++) { - if (Parent_Remote[iVertex] == Aux_Parent[jVertex]) { - Parent_Local[iVertex] = jVertex + Index_CoarseCV; - break; - } - } - - Children_Remote[iVertex] = Buffer_Receive_Children[iVertex]; - Children_Local[iVertex] = fine_grid->vertex[MarkerR][iVertex]->GetNode(); - - } - - Index_CoarseCV += Aux_Parent.size(); - - nChildren_MPI = new unsigned short [Index_CoarseCV]; - for (iParent = 0; iParent < Index_CoarseCV; iParent++) - nChildren_MPI[iParent] = 0; - - /*--- Create the final structure ---*/ - for (iVertex = 0; iVertex < nVertexR; iVertex++) { - - /*--- Be careful, it is possible that a node change the agglomeration configuration, the priority - is always, when receive the information ---*/ - - fine_grid->node[Children_Local[iVertex]]->SetParent_CV(Parent_Local[iVertex]); - node[Parent_Local[iVertex]]->SetChildren_CV(nChildren_MPI[Parent_Local[iVertex]], Children_Local[iVertex]); - nChildren_MPI[Parent_Local[iVertex]]++; - node[Parent_Local[iVertex]]->SetnChildren_CV(nChildren_MPI[Parent_Local[iVertex]]); - node[Parent_Local[iVertex]]->SetDomain(false); - - } - - /*--- Deallocate auxiliar structures ---*/ - - delete[] nChildren_MPI; - delete[] Parent_Remote; - delete[] Children_Remote; - delete[] Parent_Local; - delete[] Children_Local; - - /*--- Deallocate receive buffer ---*/ - - delete [] Buffer_Receive_Children; - delete [] Buffer_Receive_Parent; - - } - - } - - /*--- Update the number of points after the MPI agglomeration ---*/ - - nPoint = Index_CoarseCV; - - /*--- Console output with the summary of the agglomeration ---*/ - - Local_nPointCoarse = nPoint; - Local_nPointFine = fine_grid->GetnPoint(); - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&Local_nPointCoarse, &Global_nPointCoarse, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); - SU2_MPI::Allreduce(&Local_nPointFine, &Global_nPointFine, 1, MPI_UNSIGNED_LONG, MPI_SUM, MPI_COMM_WORLD); -#else - Global_nPointCoarse = Local_nPointCoarse; - Global_nPointFine = Local_nPointFine; -#endif - - su2double Coeff = 1.0, CFL = 0.0, factor = 1.5; - - if (iMesh != MESH_0) { - if (nDim == 2) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./2.); - if (nDim == 3) Coeff = pow(su2double(Global_nPointFine)/su2double(Global_nPointCoarse), 1./3.); - CFL = factor*config->GetCFL(iMesh-1)/Coeff; - config->SetCFL(iMesh, CFL); - } - - su2double ratio = su2double(Global_nPointFine)/su2double(Global_nPointCoarse); - - if (((nDim == 2) && (ratio < 2.5)) || - ((nDim == 3) && (ratio < 2.5))) { - config->SetMGLevels(iMesh-1); - } - else { - if (rank == MASTER_NODE) { - PrintingToolbox::CTablePrinter MGTable(&std::cout); - MGTable.AddColumn("MG Level", 10); - MGTable.AddColumn("CVs", 10); - MGTable.AddColumn("Aggl. Rate", 10); - MGTable.AddColumn("CFL", 10); - MGTable.SetAlign(PrintingToolbox::CTablePrinter::RIGHT); - - - if (iMesh == 1){ - MGTable.PrintHeader(); - MGTable << iMesh - 1 << Global_nPointFine << "1/1.00" << config->GetCFL(iMesh -1); - } - stringstream ss; - ss << "1/" << std::setprecision(3) << ratio; - MGTable << iMesh << Global_nPointCoarse << ss.str() << CFL; - if (iMesh == config->GetnMGLevels()){ - MGTable.PrintFooter(); - } - } - } - - delete [] copy_marker; - -} - - -CMultiGridGeometry::~CMultiGridGeometry(void) { - -} - -bool CMultiGridGeometry::SetBoundAgglomeration(unsigned long CVPoint, short marker_seed, CGeometry *fine_grid, CConfig *config) { - - bool agglomerate_CV = false; - unsigned short counter, jMarker; - - unsigned short nMarker_Max = config->GetnMarker_Max(); - - unsigned short *copy_marker = new unsigned short [nMarker_Max]; - - /*--- Basic condition, the element has not being previously agglomerated, it belongs to the domain, - and has passed some basic geometrical check ---*/ - - if ((fine_grid->node[CVPoint]->GetAgglomerate() == false) && - (fine_grid->node[CVPoint]->GetDomain()) && - (GeometricalCheck(CVPoint, fine_grid, config))) { - - /*--- If the element belong to the boundary, we must be careful ---*/ - - if (fine_grid->node[CVPoint]->GetBoundary()) { - - /*--- Identify the markers of the vertex that we want to agglomerate ---*/ - - counter = 0; - for (jMarker = 0; jMarker < fine_grid->GetnMarker(); jMarker ++) - if (fine_grid->node[CVPoint]->GetVertex(jMarker) != -1) { - copy_marker[counter] = jMarker; - counter++; - } - - /*--- The basic condition is that the aglomerated vertex must have the same physical marker, - but eventually a send-receive condition ---*/ - - /*--- Only one marker in the vertex that is going to be aglomerated ---*/ - - if (counter == 1) { - - /*--- We agglomerate if there is only a marker and is the same marker as the seed marker ---*/ - - if (copy_marker[0] == marker_seed) - agglomerate_CV = true; - - /*--- If there is only a marker, but the marker is the SEND_RECEIVE ---*/ - - if (config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) - agglomerate_CV = true; - - } - - /*--- If there are two markers in the vertex that is going to be aglomerated ---*/ - - if (counter == 2) { - - /*--- First we verify that the seed is a physical boundary ---*/ - - if (config->GetMarker_All_KindBC(marker_seed) != SEND_RECEIVE) { - - /*--- Then we check that one of the marker is equal to the seed marker, and the other is send/receive ---*/ - - if (((copy_marker[0] == marker_seed) && (config->GetMarker_All_KindBC(copy_marker[1]) == SEND_RECEIVE)) || - ((config->GetMarker_All_KindBC(copy_marker[0]) == SEND_RECEIVE) && (copy_marker[1] == marker_seed))) - agglomerate_CV = true; - } - - } - - } - - /*--- If the element belong to the domain, it is allways aglomerated ---*/ - - else { agglomerate_CV = true; } - - } - - delete [] copy_marker; - - return agglomerate_CV; - -} + Compute_Wing_LeadingTrailing(LeadingEdge[iPlane], TrailingEdge[iPlane], Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); -bool CMultiGridGeometry::GeometricalCheck(unsigned long iPoint, CGeometry *fine_grid, CConfig *config) { - - su2double max_dimension = 1.2; - - /*--- Evaluate the total size of the element ---*/ - - bool Volume = true; - su2double ratio = pow(fine_grid->node[iPoint]->GetVolume(), 1.0/su2double(nDim))*max_dimension; - su2double limit = pow(config->GetDomainVolume(), 1.0/su2double(nDim)); - if ( ratio > limit ) Volume = false; - - /*--- Evaluate the stretching of the element ---*/ - - bool Stretching = true; - - /* unsigned short iNode, iDim; - unsigned long jPoint; - su2double *Coord_i = fine_grid->node[iPoint]->GetCoord(); - su2double max_dist = 0.0 ; su2double min_dist = 1E20; - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - su2double *Coord_j = fine_grid->node[jPoint]->GetCoord(); - su2double distance = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - distance += (Coord_j[iDim]-Coord_i[iDim])*(Coord_j[iDim]-Coord_i[iDim]); - distance = sqrt(distance); - max_dist = max(distance, max_dist); - min_dist = min(distance, min_dist); - } - if ( max_dist/min_dist > 100.0 ) Stretching = false;*/ - - return (Stretching && Volume); - -} + Area[iPlane] = Compute_Area(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); -void CMultiGridGeometry::SetSuitableNeighbors(vector *Suitable_Indirect_Neighbors, unsigned long iPoint, - unsigned long Index_CoarseCV, CGeometry *fine_grid) { - - unsigned long jPoint, kPoint, lPoint; - unsigned short iNode, jNode, iNeighbor, jNeighbor, kNode; - bool SecondNeighborSeed, ThirdNeighborSeed; - vector::iterator it; - - /*--- Create a list with the first neighbors, including the seed ---*/ - - vector First_Neighbor_Points; - First_Neighbor_Points.push_back(iPoint); - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - First_Neighbor_Points.push_back(jPoint); - } - - /*--- Create a list with the second neighbors, without first, and seed neighbors ---*/ - - vector Second_Neighbor_Points, Second_Origin_Points, Suitable_Second_Neighbors; - - for (iNode = 0; iNode < fine_grid->node[iPoint]->GetnPoint(); iNode ++) { - jPoint = fine_grid->node[iPoint]->GetPoint(iNode); - - for (jNode = 0; jNode < fine_grid->node[jPoint]->GetnPoint(); jNode ++) { - kPoint = fine_grid->node[jPoint]->GetPoint(jNode); - - /*--- Check that the second neighbor do not belong to the first neighbor or the seed ---*/ - - SecondNeighborSeed = true; - for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) - if (kPoint == First_Neighbor_Points[iNeighbor]) { - SecondNeighborSeed = false; break; - } - - if (SecondNeighborSeed) { - Second_Neighbor_Points.push_back(kPoint); - Second_Origin_Points.push_back(jPoint); - } - - } - } - - /*--- Identify those second neighbors that are repeated (candidate to be added) ---*/ - - for (iNeighbor = 0; iNeighbor < Second_Neighbor_Points.size(); iNeighbor ++) - - for (jNeighbor = 0; jNeighbor < Second_Neighbor_Points.size(); jNeighbor ++) - - /*--- Repeated second neighbor with different origin ---*/ - - if ((Second_Neighbor_Points[iNeighbor] == Second_Neighbor_Points[jNeighbor]) && - (Second_Origin_Points[iNeighbor] != Second_Origin_Points[jNeighbor]) && - (iNeighbor < jNeighbor)) { - - Suitable_Indirect_Neighbors->push_back(Second_Neighbor_Points[iNeighbor]); - - /*--- Create alist with the suitable second neighbor, that we will use - to compute the third neighbors --*/ - - Suitable_Second_Neighbors.push_back(Second_Neighbor_Points[iNeighbor]); - - } - - - /*--- Remove repeated from the suitable second neighbors ---*/ - - sort(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); - it = unique(Suitable_Second_Neighbors.begin(), Suitable_Second_Neighbors.end()); - Suitable_Second_Neighbors.resize(it - Suitable_Second_Neighbors.begin()); - - /*--- Remove repeated from first neighbors ---*/ - - sort(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); - it = unique(First_Neighbor_Points.begin(), First_Neighbor_Points.end()); - First_Neighbor_Points.resize(it - First_Neighbor_Points.begin()); - - /*--- Create a list with the third neighbors, without first, second, and seed neighbors ---*/ - - vector Third_Neighbor_Points, Third_Origin_Points; - - for (jNode = 0; jNode < Suitable_Second_Neighbors.size(); jNode ++) { - kPoint = Suitable_Second_Neighbors[jNode]; - - for (kNode = 0; kNode < fine_grid->node[kPoint]->GetnPoint(); kNode ++) { - lPoint = fine_grid->node[kPoint]->GetPoint(kNode); - - /*--- Check that the third neighbor do not belong to the first neighbors or the seed ---*/ - - ThirdNeighborSeed = true; - - for (iNeighbor = 0; iNeighbor < First_Neighbor_Points.size(); iNeighbor ++) - if (lPoint == First_Neighbor_Points[iNeighbor]) { - ThirdNeighborSeed = false; - break; - } - - /*--- Check that the third neighbor do not belong to the second neighbors ---*/ + MaxThickness[iPlane] = Compute_MaxThickness(Plane_P0[iPlane], Plane_Normal[iPlane], config, Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - for (iNeighbor = 0; iNeighbor < Suitable_Second_Neighbors.size(); iNeighbor ++) - if (lPoint == Suitable_Second_Neighbors[iNeighbor]) { - ThirdNeighborSeed = false; - break; - } - - if (ThirdNeighborSeed) { - Third_Neighbor_Points.push_back(lPoint); - Third_Origin_Points.push_back(kPoint); - } - - } - } - - /*--- Identify those third neighbors that are repeated (candidate to be added) ---*/ + Chord[iPlane] = Compute_Chord(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - for (iNeighbor = 0; iNeighbor < Third_Neighbor_Points.size(); iNeighbor ++) - for (jNeighbor = 0; jNeighbor < Third_Neighbor_Points.size(); jNeighbor ++) + Twist[iPlane] = Compute_Twist(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); - /*--- Repeated second neighbor with different origin ---*/ - - if ((Third_Neighbor_Points[iNeighbor] == Third_Neighbor_Points[jNeighbor]) && - (Third_Origin_Points[iNeighbor] != Third_Origin_Points[jNeighbor]) && - (iNeighbor < jNeighbor)) { - - Suitable_Indirect_Neighbors->push_back(Third_Neighbor_Points[iNeighbor]); - - } - - /*--- Remove repeated from Suitable Indirect Neighbors List ---*/ - - sort(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); - it = unique(Suitable_Indirect_Neighbors->begin(), Suitable_Indirect_Neighbors->end()); - Suitable_Indirect_Neighbors->resize(it - Suitable_Indirect_Neighbors->begin()); - -} + LERadius[iPlane] = Compute_LERadius(Plane_P0[iPlane], Plane_Normal[iPlane], Xcoord_Airfoil[iPlane], Ycoord_Airfoil[iPlane], Zcoord_Airfoil[iPlane]); -void CMultiGridGeometry::SetPoint_Connectivity(CGeometry *fine_grid) { - - unsigned long iFinePoint, iFinePoint_Neighbor, iParent, iCoarsePoint; - unsigned short iChildren, iNode; - - /*--- Set the point surrounding a point ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { - iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); - iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); - if (iParent != iCoarsePoint) node[iCoarsePoint]->SetPoint(iParent); - } - } - } - - /*--- Set the number of neighbors variable, this is - important for JST and multigrid in parallel ---*/ - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - node[iCoarsePoint]->SetnNeighbor(node[iCoarsePoint]->GetnPoint()); - -} + ToC[iPlane] = MaxThickness[iPlane] / Chord[iPlane]; -void CMultiGridGeometry::SetVertex(CGeometry *fine_grid, CConfig *config) { - unsigned long iVertex, iFinePoint, iCoarsePoint; - unsigned short iMarker, iMarker_Tag, iChildren; - - nMarker = fine_grid->GetnMarker(); - unsigned short nMarker_Max = config->GetnMarker_Max(); - /*--- If any children node belong to the boundary then the entire control - volume will belong to the boundary ---*/ - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - if (fine_grid->node[iFinePoint]->GetBoundary()) { - node[iCoarsePoint]->SetBoundary(nMarker); - break; - } - } - - vertex = new CVertex**[nMarker]; - nVertex = new unsigned long [nMarker]; - - Tag_to_Marker = new string [nMarker_Max]; - for (iMarker_Tag = 0; iMarker_Tag < nMarker_Max; iMarker_Tag++) - Tag_to_Marker[iMarker_Tag] = fine_grid->GetMarker_Tag(iMarker_Tag); - - /*--- Compute the number of vertices to do the dimensionalization ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; - - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { - if (node[iCoarsePoint]->GetBoundary()) { - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iMarker = 0; iMarker < nMarker; iMarker ++) { - if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { - iVertex = nVertex[iMarker]; - node[iCoarsePoint]->SetVertex(iVertex, iMarker); - nVertex[iMarker]++; - } - } } + } - } - - for (iMarker = 0; iMarker < nMarker; iMarker++) { - vertex[iMarker] = new CVertex* [fine_grid->GetnVertex(iMarker)+1]; - nVertex[iMarker] = 0; - } - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - if (node[iCoarsePoint]->GetBoundary()) - for (iMarker = 0; iMarker < nMarker; iMarker ++) - node[iCoarsePoint]->SetVertex(-1, iMarker); - - for (iMarker = 0; iMarker < nMarker; iMarker++) nVertex[iMarker] = 0; - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - if (node[iCoarsePoint]->GetBoundary()) - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - for (iMarker = 0; iMarker < fine_grid->GetnMarker(); iMarker ++) { - if ((fine_grid->node[iFinePoint]->GetVertex(iMarker) != -1) && (node[iCoarsePoint]->GetVertex(iMarker) == -1)) { - iVertex = nVertex[iMarker]; - vertex[iMarker][iVertex] = new CVertex(iCoarsePoint, nDim); - node[iCoarsePoint]->SetVertex(iVertex, iMarker); - - /*--- Set the transformation to apply ---*/ - unsigned long ChildVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); - unsigned short RotationKind = fine_grid->vertex[iMarker][ChildVertex]->GetRotation_Type(); - vertex[iMarker][iVertex]->SetRotation_Type(RotationKind); - nVertex[iMarker]++; - } - } - } -} -void CMultiGridGeometry::MatchNearField(CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex, iPoint; - int iProcessor = size; + /*--- Plot the geometrical quatities ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor); - } - } - } - } - -} + for (iPlane = 0; iPlane < nPlane; iPlane++) { -void CMultiGridGeometry::MatchActuator_Disk(CConfig *config) { - - unsigned short iMarker; - unsigned long iVertex, iPoint; - int iProcessor = size; + su2double theta_deg = atan2(Plane_Normal[iPlane][1], -Plane_Normal[iPlane][2])/PI_NUMBER*180 + 180; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == ACTDISK_INLET) || - (config->GetMarker_All_KindBC(iMarker) == ACTDISK_OUTLET)) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor); + if (Xcoord_Airfoil[iPlane].size() > 1) { + if (config->GetTabular_FileFormat() == TAB_CSV) { + Nacelle_File << theta_deg <<", "<< Area[iPlane] <<", "<< MaxThickness[iPlane] <<", "<< Chord[iPlane] <<", "<< LERadius[iPlane] <<", "<< ToC[iPlane] + <<", "<< Twist[iPlane] <<", "<< LeadingEdge[iPlane][0] <<", "<< LeadingEdge[iPlane][2] + <<", "<< TrailingEdge[iPlane][0] <<", "<< TrailingEdge[iPlane][2] << endl; } - } - } - } - -} + else { + Nacelle_File << theta_deg <<" "<< Area[iPlane] <<" "<< MaxThickness[iPlane] <<" "<< Chord[iPlane] <<" "<< LERadius[iPlane] <<" "<< ToC[iPlane] + <<" "<< Twist[iPlane] <<" "<< LeadingEdge[iPlane][0] <<" "<< LeadingEdge[iPlane][2] + <<" "<< TrailingEdge[iPlane][0] <<" "<< TrailingEdge[iPlane][2] << endl; -void CMultiGridGeometry::MatchPeriodic(CConfig *config, unsigned short val_periodic) { - - unsigned short iMarker, iPeriodic, nPeriodic; - unsigned long iVertex, iPoint; - int iProcessor = rank; - - /*--- Evaluate the number of periodic boundary conditions ---*/ - - nPeriodic = config->GetnMarker_Periodic(); - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY) { - iPeriodic = config->GetMarker_All_PerBound(iMarker); - if ((iPeriodic == val_periodic) || - (iPeriodic == val_periodic + nPeriodic/2)) { - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - if (node[iPoint]->GetDomain()) { - vertex[iMarker][iVertex]->SetDonorPoint(iPoint, node[iPoint]->GetGlobalIndex(), iVertex, iMarker, iProcessor); - } } } - } - } - -} -void CMultiGridGeometry::SetControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { - - unsigned long iFinePoint, iFinePoint_Neighbor, iCoarsePoint, iEdge, iParent; - long FineEdge, CoarseEdge; - unsigned short iChildren, iNode, iDim; - bool change_face_orientation; - su2double *Normal, Coarse_Volume, Area, *NormalFace = NULL; - Normal = new su2double [nDim]; - - /*--- Compute the area of the coarse volume ---*/ - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) { - node[iCoarsePoint]->SetVolume(0.0); - Coarse_Volume = 0.0; - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - Coarse_Volume += fine_grid->node[iFinePoint]->GetVolume(); - } - node[iCoarsePoint]->SetVolume(Coarse_Volume); - } - - /*--- Update or not the values of faces at the edge ---*/ - if (action != ALLOCATE) { - for (iEdge=0; iEdge < nEdge; iEdge++) - edge[iEdge]->SetZeroValues(); - } - - for (iCoarsePoint = 0; iCoarsePoint < nPoint; iCoarsePoint ++) - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - - for (iNode = 0; iNode < fine_grid->node[iFinePoint]->GetnPoint(); iNode ++) { - iFinePoint_Neighbor = fine_grid->node[iFinePoint]->GetPoint(iNode); - iParent = fine_grid->node[iFinePoint_Neighbor]->GetParent_CV(); - if ((iParent != iCoarsePoint) && (iParent < iCoarsePoint)) { - - FineEdge = fine_grid->FindEdge(iFinePoint, iFinePoint_Neighbor); - - change_face_orientation = false; - if (iFinePoint < iFinePoint_Neighbor) change_face_orientation = true; - - CoarseEdge = FindEdge(iParent, iCoarsePoint); - - fine_grid->edge[FineEdge]->GetNormal(Normal); - - if (change_face_orientation) { - for (iDim = 0; iDim < nDim; iDim++) Normal[iDim] = -Normal[iDim]; - edge[CoarseEdge]->AddNormal(Normal); - } - else { - edge[CoarseEdge]->AddNormal(Normal); - } - } - } } - delete[] Normal; - - /*--- Check if there is a normal with null area ---*/ - - for (iEdge = 0; iEdge < nEdge; iEdge++) { - NormalFace = edge[iEdge]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; - Area = sqrt(Area); - if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; - } - -} -void CMultiGridGeometry::SetBoundControlVolume(CConfig *config, CGeometry *fine_grid, unsigned short action) { - unsigned long iCoarsePoint, iFinePoint, FineVertex, iVertex; - unsigned short iMarker, iChildren, iDim; - su2double *Normal, Area, *NormalFace = NULL; - - Normal = new su2double [nDim]; - - if (action != ALLOCATE) { - for (iMarker = 0; iMarker < nMarker; iMarker++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) - vertex[iMarker][iVertex]->SetZeroValues(); - } - - for (iMarker = 0; iMarker < nMarker; iMarker ++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iCoarsePoint = vertex[iMarker][iVertex]->GetNode(); - for (iChildren = 0; iChildren < node[iCoarsePoint]->GetnChildren_CV(); iChildren ++) { - iFinePoint = node[iCoarsePoint]->GetChildren_CV(iChildren); - if (fine_grid->node[iFinePoint]->GetVertex(iMarker)!=-1) { - FineVertex = fine_grid->node[iFinePoint]->GetVertex(iMarker); - fine_grid->vertex[iMarker][FineVertex]->GetNormal(Normal); - vertex[iMarker][iVertex]->AddNormal(Normal); - } - } - } - - delete[] Normal; - - /*--- Check if there is a normal with null area ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker ++) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - NormalFace = vertex[iMarker][iVertex]->GetNormal(); - Area = 0.0; for (iDim = 0; iDim < nDim; iDim++) Area += NormalFace[iDim]*NormalFace[iDim]; - Area = sqrt(Area); - if (Area == 0.0) for (iDim = 0; iDim < nDim; iDim++) NormalFace[iDim] = EPS*EPS; - } - -} + Nacelle_File.close(); -void CMultiGridGeometry::SetCoord(CGeometry *geometry) { - unsigned long Point_Fine, Point_Coarse; - unsigned short iChildren, iDim; - su2double Area_Parent, Area_Children; - su2double *Coordinates_Fine, *Coordinates; - Coordinates = new su2double[nDim]; - - for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { - Area_Parent = node[Point_Coarse]->GetVolume(); - for (iDim = 0; iDim < nDim; iDim++) Coordinates[iDim] = 0.0; - for (iChildren = 0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++) { - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); - Area_Children = geometry->node[Point_Fine]->GetVolume(); - Coordinates_Fine = geometry->node[Point_Fine]->GetCoord(); - for (iDim = 0; iDim < nDim; iDim++) - Coordinates[iDim] += Coordinates_Fine[iDim]*Area_Children/Area_Parent; - } - for (iDim = 0; iDim < nDim; iDim++) - node[Point_Coarse]->SetCoord(iDim, Coordinates[iDim]); - } - delete[] Coordinates; -} + Section_File.open("nacelle_slices.dat", ios::out); -void CMultiGridGeometry::SetMultiGridWallHeatFlux(CGeometry *geometry, unsigned short val_marker){ - - unsigned long Point_Fine, Point_Coarse, iVertex; - unsigned short iChildren; - long Vertex_Fine; - su2double Area_Parent, Area_Children; - su2double WallHeatFlux_Fine, WallHeatFlux_Coarse; - bool isVertex; - int numberVertexChildren; - - for(iVertex=0; iVertex < nVertex[val_marker]; iVertex++){ - Point_Coarse = vertex[val_marker][iVertex]->GetNode(); - if (node[Point_Coarse]->GetDomain()){ - Area_Parent = 0.0; - WallHeatFlux_Coarse = 0.0; - numberVertexChildren = 0; - /*--- Compute area parent by taking into account only volumes that are on the marker ---*/ - for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); - isVertex = (node[Point_Fine]->GetDomain() && geometry->node[Point_Fine]->GetVertex(val_marker) != -1); - if (isVertex){ - numberVertexChildren += 1; - Area_Parent += geometry->node[Point_Fine]->GetVolume(); - } + for (iPlane = 0; iPlane < nPlane; iPlane++) { + + if (iPlane == 0) { + Section_File << "TITLE = \"Nacelle Slices\"" << endl; + if (config->GetSystemMeasurements() == US) + Section_File << "VARIABLES = \"x (in)\", \"y (in)\", \"z (in)\", \"x2D/c\", \"y2D/c\"" << endl; + else Section_File << "VARIABLES = \"x (m)\", \"y (m)\", \"z (m)\", \"x2D/c\", \"y2D/c\"" << endl; } - /*--- Loop again and propagate values to the coarser level ---*/ - for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); - Vertex_Fine = geometry->node[Point_Fine]->GetVertex(val_marker); - isVertex = (node[Point_Fine]->GetDomain() && Vertex_Fine != -1); - if(isVertex){ - Area_Children = geometry->node[Point_Fine]->GetVolume(); - //Get the customized BC values on fine level and compute the values at coarse level - WallHeatFlux_Fine = geometry->GetCustomBoundaryHeatFlux(val_marker, Vertex_Fine); - WallHeatFlux_Coarse += WallHeatFlux_Fine*Area_Children/Area_Parent; - } + if (Xcoord_Airfoil[iPlane].size() > 1) { - } - //Set the customized BC values at coarse level - CustomBoundaryHeatFlux[val_marker][iVertex] = WallHeatFlux_Coarse; - } - } + su2double theta_deg = atan2(Plane_Normal[iPlane][1], -Plane_Normal[iPlane][2])/PI_NUMBER*180 + 180; + su2double Angle = theta_deg*PI_NUMBER/180 - 0.5*PI_NUMBER; -} + Section_File << "ZONE T=\"q = " << theta_deg << " deg\", I= " << Xcoord_Airfoil[iPlane].size() << ", F=POINT" << endl; -void CMultiGridGeometry::SetMultiGridWallTemperature(CGeometry *geometry, unsigned short val_marker){ - - unsigned long Point_Fine, Point_Coarse, iVertex; - unsigned short iChildren; - long Vertex_Fine; - su2double Area_Parent, Area_Children; - su2double WallTemperature_Fine, WallTemperature_Coarse; - bool isVertex; - int numberVertexChildren; - - for(iVertex=0; iVertex < nVertex[val_marker]; iVertex++){ - Point_Coarse = vertex[val_marker][iVertex]->GetNode(); - if (node[Point_Coarse]->GetDomain()){ - Area_Parent = 0.0; - WallTemperature_Coarse = 0.0; - numberVertexChildren = 0; - /*--- Compute area parent by taking into account only volumes that are on the marker ---*/ - for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); - isVertex = (node[Point_Fine]->GetDomain() && geometry->node[Point_Fine]->GetVertex(val_marker) != -1); - if (isVertex){ - numberVertexChildren += 1; - Area_Parent += geometry->node[Point_Fine]->GetVolume(); - } - } + for (iVertex = 0; iVertex < Xcoord_Airfoil[iPlane].size(); iVertex++) { - /*--- Loop again and propagate values to the coarser level ---*/ - for(iChildren=0; iChildren < node[Point_Coarse]->GetnChildren_CV(); iChildren++){ - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChildren); - Vertex_Fine = geometry->node[Point_Fine]->GetVertex(val_marker); - isVertex = (node[Point_Fine]->GetDomain() && Vertex_Fine != -1); - if(isVertex){ - Area_Children = geometry->node[Point_Fine]->GetVolume(); - //Get the customized BC values on fine level and compute the values at coarse level - WallTemperature_Fine = geometry->GetCustomBoundaryTemperature(val_marker, Vertex_Fine); - WallTemperature_Coarse += WallTemperature_Fine*Area_Children/Area_Parent; - } + /*--- Move to the origin ---*/ - } - //Set the customized BC values at coarse level - CustomBoundaryTemperature[val_marker][iVertex] = WallTemperature_Coarse; - } - } + su2double XValue_ = Xcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][0]; + su2double ZValue_ = Zcoord_Airfoil[iPlane][iVertex] - LeadingEdge[iPlane][2]; -} + /*--- Rotate the airfoil and divide by the chord ---*/ -void CMultiGridGeometry::SetRotationalVelocity(CConfig *config, unsigned short val_iZone, bool print) { - - unsigned long iPoint_Coarse; - su2double *RotVel, Distance[3] = {0.0,0.0,0.0}, *Coord; - su2double Center[3] = {0.0,0.0,0.0}, Omega[3] = {0.0,0.0,0.0}, L_Ref; - RotVel = new su2double [3]; - unsigned short iDim; - - /*--- Center of rotation & angular velocity vector from config. ---*/ - - for (iDim = 0; iDim < 3; iDim++){ - Center[iDim] = config->GetMotion_Origin(iDim); - Omega[iDim] = config->GetRotation_Rate(iDim)/config->GetOmega_Ref(); - } - - L_Ref = config->GetLength_Ref(); - - /*--- Loop over all nodes and set the rotational velocity. ---*/ - - for (iPoint_Coarse = 0; iPoint_Coarse < GetnPoint(); iPoint_Coarse++) { - - /*--- Get the coordinates of the current node ---*/ - - Coord = node[iPoint_Coarse]->GetCoord(); - - /*--- Calculate the non-dim. distance from the rotation center ---*/ - - Distance[0] = (Coord[0]-Center[0])/L_Ref; - Distance[1] = (Coord[1]-Center[1])/L_Ref; - Distance[2] = (Coord[2]-Center[2])/L_Ref; - - /*--- Calculate the angular velocity as omega X r ---*/ - - RotVel[0] = Omega[1]*(Distance[2]) - Omega[2]*(Distance[1]); - RotVel[1] = Omega[2]*(Distance[0]) - Omega[0]*(Distance[2]); - RotVel[2] = Omega[0]*(Distance[1]) - Omega[1]*(Distance[0]); - - /*--- Store the grid velocity at this node ---*/ - - node[iPoint_Coarse]->SetGridVel(RotVel); - - } - - delete [] RotVel; - -} + su2double ValCos = cos(Twist[iPlane]*PI_NUMBER/180.0); + su2double ValSin = sin(Twist[iPlane]*PI_NUMBER/180.0); -void CMultiGridGeometry::SetShroudVelocity(CConfig *config) { + su2double XValue = (XValue_*ValCos - ZValue_*ValSin) / Chord[iPlane]; + su2double ZValue = (ZValue_*ValCos + XValue_*ValSin) / Chord[iPlane]; - unsigned long iPoint, iVertex; - unsigned short iMarker, iMarkerShroud; - su2double RotVel[3]; + su2double XCoord = Xcoord_Airfoil[iPlane][iVertex] + config->GetNacelleLocation(0); + su2double YCoord = (Ycoord_Airfoil[iPlane][iVertex]*cos(Angle) - Zcoord_Airfoil[iPlane][iVertex]*sin(Angle)) + config->GetNacelleLocation(1); + su2double ZCoord = (Zcoord_Airfoil[iPlane][iVertex]*cos(Angle) + Ycoord_Airfoil[iPlane][iVertex]*sin(Angle)) + config->GetNacelleLocation(2); - RotVel[0] = 0.0; - RotVel[1] = 0.0; - RotVel[2] = 0.0; + /*--- Write the file ---*/ - /*--- Loop over all vertex in the shroud marker and set the rotational velocity to 0.0 ---*/ - for (iMarker = 0; iMarker < nMarker; iMarker++){ - for(iMarkerShroud=0; iMarkerShroud < config->GetnMarker_Shroud(); iMarkerShroud++){ - if(config->GetMarker_Shroud(iMarkerShroud) == config->GetMarker_All_TagBound(iMarker)){ - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - node[iPoint]->SetGridVel(RotVel); + Section_File << XCoord << " " << YCoord << " " << ZCoord << " " << XValue << " " << ZValue << endl; } } - } - } -} - -void CMultiGridGeometry::SetTranslationalVelocity(CConfig *config, unsigned short val_iZone, bool print) { - - unsigned iDim; - unsigned long iPoint_Coarse; - su2double xDot[3] = {0.0,0.0,0.0}; - - /*--- Get the translational velocity vector from config ---*/ - - for (iDim = 0; iDim < 3; iDim++){ - xDot[iDim] = config->GetTranslation_Rate(iDim)/config->GetVelocity_Ref(); - } - - /*--- Loop over all nodes and set the translational velocity ---*/ - - for (iPoint_Coarse = 0; iPoint_Coarse < nPoint; iPoint_Coarse++) { - - /*--- Store the grid velocity at this node ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - node[iPoint_Coarse]->SetGridVel(iDim,xDot[iDim]); - - } - -} -void CMultiGridGeometry::SetGridVelocity(CConfig *config, unsigned long iter) { - - /*--- Local variables ---*/ - - su2double *Coord_nP1 = NULL, *Coord_n = NULL, *Coord_nM1 = NULL; - su2double TimeStep, GridVel = 0.0; - unsigned long Point_Coarse; - unsigned short iDim; - - /*--- Compute the velocity of each node in the volume mesh ---*/ - - for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { - - /*--- Coordinates of the current point at n+1, n, & n-1 time levels ---*/ - - Coord_nM1 = node[Point_Coarse]->GetCoord_n1(); - Coord_n = node[Point_Coarse]->GetCoord_n(); - Coord_nP1 = node[Point_Coarse]->GetCoord(); - - /*--- Unsteady time step ---*/ - - TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute mesh velocity with 1st or 2nd-order approximation ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - if (config->GetTime_Marching() == DT_STEPPING_1ST) - GridVel = ( Coord_nP1[iDim] - Coord_n[iDim] ) / TimeStep; - if (config->GetTime_Marching() == DT_STEPPING_2ND) - GridVel = ( 3.0*Coord_nP1[iDim] - 4.0*Coord_n[iDim] - + 1.0*Coord_nM1[iDim] ) / (2.0*TimeStep); - - /*--- Store grid velocity for this point ---*/ - - node[Point_Coarse]->SetGridVel(iDim, GridVel); - } - } -} -void CMultiGridGeometry::SetRestricted_GridVelocity(CGeometry *fine_mesh, CConfig *config) { - - /*--- Local variables ---*/ - unsigned short iDim, iChild; - unsigned long Point_Coarse, Point_Fine; - su2double Area_Parent, Area_Child, Grid_Vel[3], *Grid_Vel_Fine; - - /*--- Loop over all coarse mesh points ---*/ - for (Point_Coarse = 0; Point_Coarse < GetnPoint(); Point_Coarse++) { - Area_Parent = node[Point_Coarse]->GetVolume(); - - /*--- Zero out the grid velocity ---*/ - for (iDim = 0; iDim < nDim; iDim++) - Grid_Vel[iDim] = 0.0; - - /*--- Loop over all of the children for this coarse CV and compute - a grid velocity based on the values in the child CVs (fine mesh). ---*/ - for (iChild = 0; iChild < node[Point_Coarse]->GetnChildren_CV(); iChild++) { - Point_Fine = node[Point_Coarse]->GetChildren_CV(iChild); - Area_Child = fine_mesh->node[Point_Fine]->GetVolume(); - Grid_Vel_Fine = fine_mesh->node[Point_Fine]->GetGridVel(); - for (iDim = 0; iDim < nDim; iDim++) - Grid_Vel[iDim] += Grid_Vel_Fine[iDim]*Area_Child/Area_Parent; - } - - /*--- Set the grid velocity for this coarse node. ---*/ - for (iDim = 0; iDim < nDim; iDim++) - node[Point_Coarse]->SetGridVel(iDim, Grid_Vel[iDim]); - } -} + Section_File.close(); -void CMultiGridGeometry::FindNormal_Neighbor(CConfig *config) { - - unsigned short iMarker, iDim; - unsigned long iPoint, iVertex; - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - - if (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE && - config->GetMarker_All_KindBC(iMarker) != INTERFACE_BOUNDARY && - config->GetMarker_All_KindBC(iMarker) != NEARFIELD_BOUNDARY ) { - - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - - iPoint = vertex[iMarker][iVertex]->GetNode(); - - /*--- If the node belong to the domain ---*/ - if (node[iPoint]->GetDomain()) { - - /*--- Compute closest normal neighbor ---*/ - su2double cos_max, scalar_prod, norm_vect, norm_Normal, cos_alpha, diff_coord; - unsigned long Point_Normal = 0, jPoint; - unsigned short iNeigh; - su2double *Normal = vertex[iMarker][iVertex]->GetNormal(); - cos_max = -1.0; - for (iNeigh = 0; iNeigh < node[iPoint]->GetnPoint(); iNeigh++) { - jPoint = node[iPoint]->GetPoint(iNeigh); - scalar_prod = 0.0; norm_vect = 0.0; norm_Normal = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - diff_coord = node[jPoint]->GetCoord(iDim)-node[iPoint]->GetCoord(iDim); - scalar_prod += diff_coord*Normal[iDim]; - norm_vect += diff_coord*diff_coord; - norm_Normal += Normal[iDim]*Normal[iDim]; - } - norm_vect = sqrt(norm_vect); - norm_Normal = sqrt(norm_Normal); - cos_alpha = scalar_prod/(norm_vect*norm_Normal); - - /*--- Get maximum cosine (not minimum because normals are oriented inwards) ---*/ - if (cos_alpha >= cos_max) { - Point_Normal = jPoint; - cos_max = cos_alpha; - } - } - vertex[iMarker][iVertex]->SetNormal_Neighbor(Point_Normal); - } + /*--- Compute the wing volume using a composite Simpson's rule ---*/ + + Nacelle_Volume = 0.0; + for (iPlane = 0; iPlane < nPlane-2; iPlane+=2) { + if (Xcoord_Airfoil[iPlane].size() > 1) { + Nacelle_Volume += (1.0/3.0)*dAngle*(Area[iPlane] + 4.0*Area[iPlane+1] + Area[iPlane+2]); } } - } -} + /*--- Evaluate Max and Min quantities ---*/ -void CMultiGridGeometry::SetGeometryPlanes(CConfig *config) { - bool loop_on; - unsigned short iMarker = 0; - su2double auxXCoord, auxYCoord, auxZCoord, *Face_Normal = NULL, auxArea, *Xcoord = NULL, *Ycoord = NULL, *Zcoord = NULL, *FaceArea = NULL; - unsigned long jVertex, iVertex, ixCoord, iPoint, iVertex_Wall, nVertex_Wall = 0; - - /*--- Compute the total number of points on the near-field ---*/ - nVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - nVertex_Wall += nVertex[iMarker]; - - - /*--- Create an array with all the coordinates, points, pressures, face area, - equivalent area, and nearfield weight ---*/ - Xcoord = new su2double[nVertex_Wall]; - Ycoord = new su2double[nVertex_Wall]; - if (nDim == 3) Zcoord = new su2double[nVertex_Wall]; - FaceArea = new su2double[nVertex_Wall]; - - /*--- Copy the boundary information to an array ---*/ - iVertex_Wall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) - if ((config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) || - (config->GetMarker_All_KindBC(iMarker) == ISOTHERMAL) || - (config->GetMarker_All_KindBC(iMarker) == EULER_WALL) ) - for (iVertex = 0; iVertex < nVertex[iMarker]; iVertex++) { - iPoint = vertex[iMarker][iVertex]->GetNode(); - Xcoord[iVertex_Wall] = node[iPoint]->GetCoord(0); - Ycoord[iVertex_Wall] = node[iPoint]->GetCoord(1); - if (nDim==3) Zcoord[iVertex_Wall] = node[iPoint]->GetCoord(2); - Face_Normal = vertex[iMarker][iVertex]->GetNormal(); - FaceArea[iVertex_Wall] = fabs(Face_Normal[nDim-1]); - iVertex_Wall ++; - } - - - //vector XCoordList; - vector::iterator IterXCoordList; - - for (iVertex = 0; iVertex < nVertex_Wall; iVertex++) - XCoordList.push_back(Xcoord[iVertex]); - - sort( XCoordList.begin(), XCoordList.end()); - IterXCoordList = unique( XCoordList.begin(), XCoordList.end()); - XCoordList.resize( IterXCoordList - XCoordList.begin() ); - - /*--- Create vectors and distribute the values among the different PhiAngle queues ---*/ - Xcoord_plane.resize(XCoordList.size()); - Ycoord_plane.resize(XCoordList.size()); - if (nDim==3) Zcoord_plane.resize(XCoordList.size()); - FaceArea_plane.resize(XCoordList.size()); - Plane_points.resize(XCoordList.size()); - - - su2double dist_ratio; - unsigned long iCoord; - - /*--- Distribute the values among the different PhiAngles ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++) { - if (node[iPoint]->GetDomain()) { - loop_on = true; - for (ixCoord = 0; ixCoord < XCoordList.size()-1 && loop_on; ixCoord++) { - dist_ratio = (node[iPoint]->GetCoord(0) - XCoordList[ixCoord])/(XCoordList[ixCoord+1]- XCoordList[ixCoord]); - if (dist_ratio >= 0 && dist_ratio <= 1.0) { - if (dist_ratio <= 0.5) iCoord = ixCoord; - else iCoord = ixCoord+1; - Xcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(0) ); - Ycoord_plane[iCoord].push_back(node[iPoint]->GetCoord(1) ); - if (nDim==3) Zcoord_plane[iCoord].push_back(node[iPoint]->GetCoord(2) ); - FaceArea_plane[iCoord].push_back(node[iPoint]->GetVolume()); ///// CHECK AREA CALCULATION - Plane_points[iCoord].push_back(iPoint ); - loop_on = false; - } - } + Nacelle_MaxMaxThickness = -1E6; Nacelle_MinMaxThickness = 1E6; Nacelle_MinChord = 1E6; Nacelle_MaxChord = -1E6; + Nacelle_MinLERadius = 1E6; Nacelle_MaxLERadius = -1E6; Nacelle_MinToC = 1E6; Nacelle_MaxToC = -1E6; + Nacelle_MaxTwist = -1E6; + + for (iPlane = 0; iPlane < nPlane; iPlane++) { + if (MaxThickness[iPlane] != 0.0) Nacelle_MinMaxThickness = min(Nacelle_MinMaxThickness, MaxThickness[iPlane]); + Nacelle_MaxMaxThickness = max(Nacelle_MaxMaxThickness, MaxThickness[iPlane]); + if (Chord[iPlane] != 0.0) Nacelle_MinChord = min(Nacelle_MinChord, Chord[iPlane]); + Nacelle_MaxChord = max(Nacelle_MaxChord, Chord[iPlane]); + if (LERadius[iPlane] != 0.0) Nacelle_MinLERadius = min(Nacelle_MinLERadius, LERadius[iPlane]); + Nacelle_MaxLERadius = max(Nacelle_MaxLERadius, LERadius[iPlane]); + if (ToC[iPlane] != 0.0) Nacelle_MinToC = min(Nacelle_MinToC, ToC[iPlane]); + Nacelle_MaxToC = max(Nacelle_MaxToC, ToC[iPlane]); + Nacelle_ObjFun_MinToC = sqrt((Nacelle_MinToC - 0.07)*(Nacelle_MinToC - 0.07)); + Nacelle_MaxTwist = max(Nacelle_MaxTwist, fabs(Twist[iPlane])); } - } - - unsigned long auxPoint; - /*--- Order the arrays in ascending values of y ---*/ - for (ixCoord = 0; ixCoord < XCoordList.size(); ixCoord++) - for (iVertex = 0; iVertex < Xcoord_plane[ixCoord].size(); iVertex++) - for (jVertex = 0; jVertex < Xcoord_plane[ixCoord].size() - 1 - iVertex; jVertex++) - if (Ycoord_plane[ixCoord][jVertex] > Ycoord_plane[ixCoord][jVertex+1]) { - auxXCoord = Xcoord_plane[ixCoord][jVertex]; Xcoord_plane[ixCoord][jVertex] = Xcoord_plane[ixCoord][jVertex+1]; Xcoord_plane[ixCoord][jVertex+1] = auxXCoord; - auxYCoord = Ycoord_plane[ixCoord][jVertex]; Ycoord_plane[ixCoord][jVertex] = Ycoord_plane[ixCoord][jVertex+1]; Ycoord_plane[ixCoord][jVertex+1] = auxYCoord; - auxPoint = Plane_points[ixCoord][jVertex]; Plane_points[ixCoord][jVertex] = Plane_points[ixCoord][jVertex+1]; Plane_points[ixCoord][jVertex+1] = auxPoint; - if (nDim==3) { - auxZCoord = Zcoord_plane[ixCoord][jVertex]; Zcoord_plane[ixCoord][jVertex] = Zcoord_plane[ixCoord][jVertex+1]; Zcoord_plane[ixCoord][jVertex+1] = auxZCoord; - } - auxArea = FaceArea_plane[ixCoord][jVertex]; FaceArea_plane[ixCoord][jVertex] = FaceArea_plane[ixCoord][jVertex+1]; FaceArea_plane[ixCoord][jVertex+1] = auxArea; - } - - /*--- Delete structures ---*/ - delete[] Xcoord; delete[] Ycoord; - if (Zcoord != NULL) delete[] Zcoord; - delete[] FaceArea; -} -CDummyGeometry::CDummyGeometry(CConfig *config){ - - size = SU2_MPI::GetSize(); - rank = SU2_MPI::GetRank(); - - nEdge = 0; - nPoint = 0; - nPointDomain = 0; - nPointNode = 0; - nElem = 0; - nMarker = 0; - nZone = config->GetnZone(); - - nElem_Bound = NULL; - Tag_to_Marker = NULL; - elem = NULL; - face = NULL; - bound = NULL; - node = NULL; - edge = NULL; - vertex = NULL; - nVertex = NULL; - newBound = NULL; - nNewElem_Bound = NULL; - Marker_All_SendRecv = NULL; - - XCoordList.clear(); - Xcoord_plane.clear(); - Ycoord_plane.clear(); - Zcoord_plane.clear(); - FaceArea_plane.clear(); - Plane_points.clear(); - - /*--- Arrays for defining the linear partitioning ---*/ - - beg_node = NULL; - end_node = NULL; - - nPointLinear = NULL; - nPointCumulative = NULL; - - /*--- Containers for customized boundary conditions ---*/ - - CustomBoundaryHeatFlux = NULL; //Customized heat flux wall - CustomBoundaryTemperature = NULL; //Customized temperature wall - - /*--- MPI point-to-point data structures ---*/ - - nP2PSend = 0; - nP2PRecv = 0; - - countPerPoint = 0; - - bufD_P2PSend = NULL; - bufD_P2PRecv = NULL; - - bufS_P2PSend = NULL; - bufS_P2PRecv = NULL; - - req_P2PSend = NULL; - req_P2PRecv = NULL; - - nPoint_P2PSend = new int[size]; - nPoint_P2PRecv = new int[size]; - - Neighbors_P2PSend = NULL; - Neighbors_P2PRecv = NULL; - - Local_Point_P2PSend = NULL; - Local_Point_P2PRecv = NULL; - - /*--- MPI periodic data structures ---*/ - - nPeriodicSend = 0; - nPeriodicRecv = 0; - - countPerPeriodicPoint = 0; - - bufD_PeriodicSend = NULL; - bufD_PeriodicRecv = NULL; - - bufS_PeriodicSend = NULL; - bufS_PeriodicRecv = NULL; - - req_PeriodicSend = NULL; - req_PeriodicRecv = NULL; - - nPoint_PeriodicSend = NULL; - nPoint_PeriodicRecv = NULL; - - Neighbors_PeriodicSend = NULL; - Neighbors_PeriodicRecv = NULL; - - Local_Point_PeriodicSend = NULL; - Local_Point_PeriodicRecv = NULL; - - Local_Marker_PeriodicSend = NULL; - Local_Marker_PeriodicRecv = NULL; - - nVertex = new unsigned long[config->GetnMarker_All()]; - - for (unsigned short iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ - nVertex[iMarker] = 0; } - - Tag_to_Marker = new string[config->GetnMarker_All()]; - - for (unsigned short iRank = 0; iRank < size; iRank++){ - nPoint_P2PRecv[iRank] = 0; - nPoint_P2PSend[iRank] = 0; - } - - nDim = CConfig::GetnDim(config->GetMesh_FileName(), config->GetMesh_FileFormat()); - - config->SetnSpanWiseSections(0); + + /*--- Free memory for the section cuts ---*/ + + delete [] Xcoord_Airfoil; + delete [] Ycoord_Airfoil; + delete [] Zcoord_Airfoil; + delete [] Variable_Airfoil; + + for (iPlane = 0; iPlane < nPlane; iPlane++) + delete [] LeadingEdge[iPlane]; + delete [] LeadingEdge; + + for (iPlane = 0; iPlane < nPlane; iPlane++) + delete [] TrailingEdge[iPlane]; + delete [] TrailingEdge; + + for (iPlane = 0; iPlane < nPlane; iPlane++) + delete [] Plane_P0[iPlane]; + delete [] Plane_P0; + + for (iPlane = 0; iPlane < nPlane; iPlane++) + delete [] Plane_Normal[iPlane]; + delete [] Plane_Normal; + + delete [] Area; + delete [] MaxThickness; + delete [] Chord; + delete [] LERadius; + delete [] ToC; + delete [] Twist; + } -CDummyGeometry::~CDummyGeometry(){} diff --git a/Common/src/geometry/meson.build b/Common/src/geometry/meson.build new file mode 100644 index 000000000000..80cb16d8f145 --- /dev/null +++ b/Common/src/geometry/meson.build @@ -0,0 +1,5 @@ +common_src += files(['CGeometry.cpp', + 'CPhysicalGeometry.cpp', + 'CMultiGridGeometry.cpp', + 'CDummyGeometry.cpp']) + diff --git a/Common/src/geometry_structure_fem_part.cpp b/Common/src/geometry_structure_fem_part.cpp index 6cf914191d45..80bded9b6d13 100644 --- a/Common/src/geometry_structure_fem_part.cpp +++ b/Common/src/geometry_structure_fem_part.cpp @@ -25,7 +25,11 @@ * License along with SU2. If not, see . */ -#include "../include/geometry_structure.hpp" +#include "../include/geometry/CPhysicalGeometry.hpp" +#include "../include/fem_standard_element.hpp" +#ifdef HAVE_CGNS +#include "../include/fem_cgns_elements.hpp" +#endif #include "../include/adt_structure.hpp" #include "../include/blas_structure.hpp" #include @@ -33,43 +37,6 @@ #include /*--- Epsilon definition ---*/ -bool CUnsignedLong2T::operator<(const CUnsignedLong2T &other) const { - if(long0 != other.long0) return (long0 < other.long0); - if(long1 != other.long1) return (long1 < other.long1); - - return false; -} - -bool CUnsignedLong2T::operator==(const CUnsignedLong2T &other) const { - if(long0 != other.long0) return false; - if(long1 != other.long1) return false; - - return true; -} - -void CUnsignedLong2T::Copy(const CUnsignedLong2T &other) { - long0 = other.long0; - long1 = other.long1; -} - -bool CUnsignedShort2T::operator<(const CUnsignedShort2T &other) const { - if(short0 != other.short0) return (short0 < other.short0); - if(short1 != other.short1) return (short1 < other.short1); - - return false; -} - -bool CUnsignedShort2T::operator==(const CUnsignedShort2T &other) const { - if(short0 != other.short0) return false; - if(short1 != other.short1) return false; - - return true; -} - -void CUnsignedShort2T::Copy(const CUnsignedShort2T &other) { - short0 = other.short0; - short1 = other.short1; -} CFaceOfElement::CFaceOfElement() { nCornerPoints = 0; diff --git a/Common/src/meson.build b/Common/src/meson.build index 8408df37674a..ea7098f10a8d 100644 --- a/Common/src/meson.build +++ b/Common/src/meson.build @@ -6,7 +6,6 @@ common_src =files(['geometry_structure_fem_part.cpp', 'fem_integration_rules.cpp', 'config_structure.cpp', 'dual_grid_structure.cpp', - 'geometry_structure.cpp', 'blas_structure.cpp', 'ad_structure.cpp', 'grid_movement_structure.cpp', @@ -29,6 +28,7 @@ common_src =files(['geometry_structure_fem_part.cpp', subdir('linear_algebra') subdir('toolboxes') +subdir('geometry') subdir('geometry/elements') if get_option('enable-normal') diff --git a/SU2_CFD/include/CMarkerProfileReaderFVM.hpp b/SU2_CFD/include/CMarkerProfileReaderFVM.hpp index 39e30bbecf65..315a9ed2a123 100644 --- a/SU2_CFD/include/CMarkerProfileReaderFVM.hpp +++ b/SU2_CFD/include/CMarkerProfileReaderFVM.hpp @@ -1,4 +1,3 @@ - /*! * \file CMarkerProfileReaderFVM.hpp * \brief Header file for the class CMarkerProfileReaderFVM. @@ -46,7 +45,7 @@ #include "../../Common/include/mpi_structure.hpp" #include "../../Common/include/config_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" using namespace std; diff --git a/SU2_CFD/include/SU2_CFD.hpp b/SU2_CFD/include/SU2_CFD.hpp index 79e9d1a9d4ea..142649fb187b 100644 --- a/SU2_CFD/include/SU2_CFD.hpp +++ b/SU2_CFD/include/SU2_CFD.hpp @@ -43,7 +43,7 @@ #include "output/COutput.hpp" #include "numerics_structure.hpp" #include "../../Common/include/fem_geometry_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" #include "../../Common/include/grid_movement_structure.hpp" #include "../../Common/include/config_structure.hpp" #include "../../Common/include/interpolation_structure.hpp" diff --git a/SU2_CFD/include/definition_structure.hpp b/SU2_CFD/include/definition_structure.hpp index add7932a6759..9fda34c18fa6 100644 --- a/SU2_CFD/include/definition_structure.hpp +++ b/SU2_CFD/include/definition_structure.hpp @@ -33,7 +33,7 @@ #include #include "../../Common/include/fem_geometry_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" #include "../../Common/include/config_structure.hpp" using namespace std; diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index 5024a8c1f07b..bcfc4882ac43 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -47,7 +47,7 @@ #include "../interfaces/fsi/CDiscAdjDisplacementsInterfaceLegacy.hpp" #include "../solvers/CDiscAdjMeshSolver.hpp" #include "../solvers/CMeshSolver.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../../Common/include/grid_movement_structure.hpp" #include "../../../Common/include/config_structure.hpp" #include "../../../Common/include/interpolation_structure.hpp" diff --git a/SU2_CFD/include/integration_structure.hpp b/SU2_CFD/include/integration_structure.hpp index 38617d770a4b..a5c22c7b7771 100644 --- a/SU2_CFD/include/integration_structure.hpp +++ b/SU2_CFD/include/integration_structure.hpp @@ -36,7 +36,7 @@ #include #include "solver_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" #include "../../Common/include/config_structure.hpp" using namespace std; diff --git a/SU2_CFD/include/interfaces/CInterface.hpp b/SU2_CFD/include/interfaces/CInterface.hpp index feaa0c1a6569..9e8193c1a427 100644 --- a/SU2_CFD/include/interfaces/CInterface.hpp +++ b/SU2_CFD/include/interfaces/CInterface.hpp @@ -40,7 +40,7 @@ #include #include "../../../Common/include/config_structure.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../solver_structure.hpp" using namespace std; diff --git a/SU2_CFD/include/iteration_structure.hpp b/SU2_CFD/include/iteration_structure.hpp index 4d12f3ab74a8..e8791ebc755f 100644 --- a/SU2_CFD/include/iteration_structure.hpp +++ b/SU2_CFD/include/iteration_structure.hpp @@ -36,7 +36,7 @@ #include "integration_structure.hpp" #include "output/COutput.hpp" #include "numerics_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" #include "../../Common/include/grid_movement_structure.hpp" #include "../../Common/include/config_structure.hpp" diff --git a/SU2_CFD/include/output/filewriter/CSurfaceFVMDataSorter.hpp b/SU2_CFD/include/output/filewriter/CSurfaceFVMDataSorter.hpp index 693d996d7474..33016eb2c58f 100644 --- a/SU2_CFD/include/output/filewriter/CSurfaceFVMDataSorter.hpp +++ b/SU2_CFD/include/output/filewriter/CSurfaceFVMDataSorter.hpp @@ -1,6 +1,6 @@ /*! * \file CSurfaceFVMDataSorter.hpp - * \brief Headers fo the surface FVM data sorter class. + * \brief Headers for the surface FVM data sorter class. * \author T. Albring * \version 7.0.0 "Blackbird" * diff --git a/SU2_CFD/include/solver_structure.hpp b/SU2_CFD/include/solver_structure.hpp index eeca77acc5af..f57c8e048498 100644 --- a/SU2_CFD/include/solver_structure.hpp +++ b/SU2_CFD/include/solver_structure.hpp @@ -47,7 +47,7 @@ #include "numerics_structure.hpp" #include "sgs_model.hpp" #include "../../Common/include/fem_geometry_structure.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CGeometry.hpp" #include "../../Common/include/config_structure.hpp" #include "../../Common/include/linear_algebra/CSysMatrix.hpp" #include "../../Common/include/linear_algebra/CSysVector.hpp" @@ -6878,7 +6878,8 @@ class CEulerSolver : public CSolver { * \param[in] pressure_mix - value of the mixed-out avaraged pressure. * \param[in] density_miz - value of the mixed-out avaraged density. */ - void MixedOut_Average (CConfig *config, su2double val_init_pressure, su2double *val_Averaged_Flux, su2double *val_normal, su2double& pressure_mix, su2double& density_mix); + void MixedOut_Average (CConfig *config, su2double val_init_pressure, const su2double *val_Averaged_Flux, + const su2double *val_normal, su2double& pressure_mix, su2double& density_mix); /*! * \brief It gathers into the master node average quantities at inflow and outflow needed for turbomachinery analysis. @@ -6893,7 +6894,8 @@ class CEulerSolver : public CSolver { * \param[in] turboNormal - normal vector in the turbomachinery frame of reference. * \param[in] turboVelocity - velocity vector in the turbomachinery frame of reference. */ - void ComputeTurboVelocity(su2double *cartesianVelocity, su2double *turboNormal, su2double *turboVelocity, unsigned short marker_flag, unsigned short marker_kindturb); + void ComputeTurboVelocity(const su2double *cartesianVelocity, const su2double *turboNormal, su2double *turboVelocity, + unsigned short marker_flag, unsigned short marker_kindturb); /*! * \brief it take a velocity in the cartesian reference of framework and transform into the turbomachinery frame of reference. @@ -6901,7 +6903,8 @@ class CEulerSolver : public CSolver { * \param[in] turboNormal - normal vector in the turbomachinery frame of reference. * \param[in] turboVelocity - velocity vector in the turbomachinery frame of reference. */ - void ComputeBackVelocity(su2double *turboVelocity, su2double *turboNormal, su2double *cartesianVelocity, unsigned short marker_flag, unsigned short marker_kindturb); + void ComputeBackVelocity(const su2double *turboVelocity, const su2double *turboNormal, su2double *cartesianVelocity, + unsigned short marker_flag, unsigned short marker_kindturb); /*! * \brief Provide the average density at the boundary of interest. diff --git a/SU2_CFD/include/solver_structure.inl b/SU2_CFD/include/solver_structure.inl index ab58611cd8d7..9a8fc6ddd939 100644 --- a/SU2_CFD/include/solver_structure.inl +++ b/SU2_CFD/include/solver_structure.inl @@ -1600,7 +1600,8 @@ inline void CEulerSolver::SetOmegaOut(su2double value, unsigned short inMarkerTP inline void CEulerSolver::SetNuOut(su2double value, unsigned short inMarkerTP, unsigned short valSpan){NuOut[inMarkerTP][valSpan] = value;} -inline void CEulerSolver::ComputeTurboVelocity(su2double *cartesianVelocity, su2double *turboNormal, su2double *turboVelocity, unsigned short marker_flag, unsigned short kind_turb) { +inline void CEulerSolver::ComputeTurboVelocity(const su2double *cartesianVelocity, const su2double *turboNormal, su2double *turboVelocity, + unsigned short marker_flag, unsigned short kind_turb) { if ((kind_turb == AXIAL && nDim == 3) || (kind_turb == CENTRIPETAL_AXIAL && marker_flag == OUTFLOW) || (kind_turb == AXIAL_CENTRIFUGAL && marker_flag == INFLOW) ){ turboVelocity[2] = turboNormal[0]*cartesianVelocity[0] + cartesianVelocity[1]*turboNormal[1]; @@ -1619,7 +1620,8 @@ inline void CEulerSolver::ComputeTurboVelocity(su2double *cartesianVelocity, su2 } } -inline void CEulerSolver::ComputeBackVelocity(su2double *turboVelocity, su2double *turboNormal, su2double *cartesianVelocity, unsigned short marker_flag, unsigned short kind_turb){ +inline void CEulerSolver::ComputeBackVelocity(const su2double *turboVelocity, const su2double *turboNormal, su2double *cartesianVelocity, + unsigned short marker_flag, unsigned short kind_turb){ if ((kind_turb == AXIAL && nDim == 3) || (kind_turb == CENTRIPETAL_AXIAL && marker_flag == OUTFLOW) || (kind_turb == AXIAL_CENTRIFUGAL && marker_flag == INFLOW)){ cartesianVelocity[0] = turboVelocity[2]*turboNormal[0] - turboVelocity[1]*turboNormal[1]; diff --git a/SU2_CFD/src/CMarkerProfileReaderFVM.cpp b/SU2_CFD/src/CMarkerProfileReaderFVM.cpp index 11a05b555d8b..8f8b942e2938 100644 --- a/SU2_CFD/src/CMarkerProfileReaderFVM.cpp +++ b/SU2_CFD/src/CMarkerProfileReaderFVM.cpp @@ -2,24 +2,14 @@ * \file CMarkerProfileReaderFVM.cpp * \brief Class that handles the reading of marker profile files. * \author T. Economon - * \version 6.2.0 "Falcon" + * \version 7.0.0 "Blackbird" * - * The current SU2 release has been coordinated by the - * SU2 International Developers Society - * with selected contributions from the open-source community. + * SU2 Project Website: https://su2code.github.io * - * The main research teams contributing to the current release are: - * - Prof. Juan J. Alonso's group at Stanford University. - * - Prof. Piero Colonna's group at Delft University of Technology. - * - Prof. Nicolas R. Gauger's group at Kaiserslautern University of Technology. - * - Prof. Alberto Guardone's group at Polytechnic University of Milan. - * - Prof. Rafael Palacios' group at Imperial College London. - * - Prof. Vincent Terrapon's group at the University of Liege. - * - Prof. Edwin van der Weide's group at the University of Twente. - * - Lab. of New Concepts in Aeronautics at Tech. Institute of Aeronautics. + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) * - * Copyright 2012-2019, Francisco D. Palacios, Thomas D. Economon, - * Tim Albring, and the SU2 contributors. + * Copyright 2012-2019, 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 diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 2ca1e23a805f..fa341db4d593 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -28,6 +28,10 @@ #include "../../include/drivers/CDriver.hpp" #include "../../include/definition_structure.hpp" +#include "../../../Common/include/geometry/CDummyGeometry.hpp" +#include "../../../Common/include/geometry/CPhysicalGeometry.hpp" +#include "../../../Common/include/geometry/CMultiGridGeometry.hpp" + #include "../../include/numerics/elasticity/CFEALinearElasticity.hpp" #include "../../include/numerics/elasticity/CFEAMeshElasticity.hpp" #include "../../include/numerics/elasticity/CFEM_NeoHookean_Comp.hpp" @@ -3623,7 +3627,7 @@ void CDriver::StaticMesh_Preprocessing(CConfig *config, CGeometry** geometry, CS rotating reference frame. ---*/ for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++){ - geometry[iMGlevel]->SetRotationalVelocity(config, iZone, true); + geometry[iMGlevel]->SetRotationalVelocity(config, true); geometry[iMGlevel]->SetShroudVelocity(config); } @@ -3641,7 +3645,7 @@ void CDriver::StaticMesh_Preprocessing(CConfig *config, CGeometry** geometry, CS /*--- Set the translational velocity on all grid levels. ---*/ for (iMGlevel = 0; iMGlevel <= config_container[ZONE_0]->GetnMGLevels(); iMGlevel++) - geometry_container[iZone][INST_0][iMGlevel]->SetTranslationalVelocity(config, iZone, true); + geometry_container[iZone][INST_0][iMGlevel]->SetTranslationalVelocity(config, true); break; @@ -4340,7 +4344,7 @@ bool CTurbomachineryDriver::Monitor(unsigned long ExtIter) { cout << endl << " Updated rotating frame grid velocities"; cout << " for zone " << iZone << "." << endl; } - geometry_container[iZone][INST_0][MESH_0]->SetRotationalVelocity(config_container[iZone], iZone, print); + geometry_container[iZone][INST_0][MESH_0]->SetRotationalVelocity(config_container[iZone], print); geometry_container[iZone][INST_0][MESH_0]->SetShroudVelocity(config_container[iZone]); } } diff --git a/SU2_CFD/src/interfaces/CInterface.cpp b/SU2_CFD/src/interfaces/CInterface.cpp index c638f7bbbc9c..51313deee561 100644 --- a/SU2_CFD/src/interfaces/CInterface.cpp +++ b/SU2_CFD/src/interfaces/CInterface.cpp @@ -441,7 +441,8 @@ void CInterface::PreprocessAverage(CGeometry *donor_geometry, CGeometry *target_ unsigned short iSpan,jSpan, tSpan = 0, kSpan = 0, nSpanDonor, nSpanTarget, Donor_Flag = 0, Target_Flag = 0; int Marker_Donor = -1, Marker_Target = -1; - su2double *SpanValuesDonor, *SpanValuesTarget, dist, test, dist2, test2; + const su2double *SpanValuesDonor, *SpanValuesTarget; + su2double dist, test, dist2, test2; #ifdef HAVE_MPI int iSize; diff --git a/SU2_CFD/src/iteration_structure.cpp b/SU2_CFD/src/iteration_structure.cpp index b6565cc394a1..d06da0fdbf16 100644 --- a/SU2_CFD/src/iteration_structure.cpp +++ b/SU2_CFD/src/iteration_structure.cpp @@ -1190,11 +1190,7 @@ void CHeatIteration::Preprocess(COutput *output, CVolumetricMovement ***grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, - unsigned short val_iInst) { - - unsigned long OuterIter = config[val_iZone]->GetOuterIter(); - -} + unsigned short val_iInst) { } void CHeatIteration::Iterate(COutput *output, CIntegration ****integration, diff --git a/SU2_CFD/src/output/CAdjElasticityOutput.cpp b/SU2_CFD/src/output/CAdjElasticityOutput.cpp index a41ec7f86ab8..8e47cce60af0 100644 --- a/SU2_CFD/src/output/CAdjElasticityOutput.cpp +++ b/SU2_CFD/src/output/CAdjElasticityOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CAdjElasticityOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CAdjElasticityOutput::CAdjElasticityOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CAdjFlowCompOutput.cpp b/SU2_CFD/src/output/CAdjFlowCompOutput.cpp index b020de0dad09..526416815a14 100644 --- a/SU2_CFD/src/output/CAdjFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CAdjFlowCompOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CAdjFlowOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CAdjFlowCompOutput::CAdjFlowCompOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CAdjFlowIncOutput.cpp b/SU2_CFD/src/output/CAdjFlowIncOutput.cpp index 6d6ae55ed8a0..c10140927ac9 100644 --- a/SU2_CFD/src/output/CAdjFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CAdjFlowIncOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CAdjFlowIncOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CAdjFlowIncOutput::CAdjFlowIncOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CAdjHeatOutput.cpp b/SU2_CFD/src/output/CAdjHeatOutput.cpp index bbbf4b6bb8d4..2fc086d09643 100644 --- a/SU2_CFD/src/output/CAdjHeatOutput.cpp +++ b/SU2_CFD/src/output/CAdjHeatOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CAdjHeatOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CAdjHeatOutput::CAdjHeatOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CBaselineOutput.cpp b/SU2_CFD/src/output/CBaselineOutput.cpp index 705043e9ac8b..7a8fde8e5ba7 100644 --- a/SU2_CFD/src/output/CBaselineOutput.cpp +++ b/SU2_CFD/src/output/CBaselineOutput.cpp @@ -29,7 +29,7 @@ #include "../../include/output/CBaselineOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CBaselineOutput::CBaselineOutput(CConfig *config, unsigned short nDim, CSolver* solver) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CElasticityOutput.cpp b/SU2_CFD/src/output/CElasticityOutput.cpp index e1901fa26cef..98080abbc820 100644 --- a/SU2_CFD/src/output/CElasticityOutput.cpp +++ b/SU2_CFD/src/output/CElasticityOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CElasticityOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CElasticityOutput::CElasticityOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CFlowCompFEMOutput.cpp b/SU2_CFD/src/output/CFlowCompFEMOutput.cpp index 07d2019018d7..26c494f08595 100644 --- a/SU2_CFD/src/output/CFlowCompFEMOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompFEMOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CFlowCompFEMOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CFlowCompFEMOutput::CFlowCompFEMOutput(CConfig *config, unsigned short nDim) : CFlowOutput(config, nDim, true) { diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index b5cda4f9fa25..de4f4d1e4775 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CFlowCompOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CFlowCompOutput::CFlowCompOutput(CConfig *config, unsigned short nDim) : CFlowOutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index ae6b35c5e3fa..2c4e1e59da8d 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -28,7 +28,7 @@ #include "../../include/output/CFlowIncOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CFlowIncOutput::CFlowIncOutput(CConfig *config, unsigned short nDim) : CFlowOutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 1697f2609290..576dbd74310e 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -26,7 +26,7 @@ */ #include "../../include/output/CFlowOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CFlowOutput::CFlowOutput(CConfig *config, unsigned short nDim, bool fem_output) : COutput (config, nDim, fem_output){ diff --git a/SU2_CFD/src/output/CHeatOutput.cpp b/SU2_CFD/src/output/CHeatOutput.cpp index f618a057a513..7996de870a0f 100644 --- a/SU2_CFD/src/output/CHeatOutput.cpp +++ b/SU2_CFD/src/output/CHeatOutput.cpp @@ -27,7 +27,7 @@ #include "../../include/output/CHeatOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" CHeatOutput::CHeatOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/CMeshOutput.cpp b/SU2_CFD/src/output/CMeshOutput.cpp index e2d893fff6e3..94b81a6c0dd7 100644 --- a/SU2_CFD/src/output/CMeshOutput.cpp +++ b/SU2_CFD/src/output/CMeshOutput.cpp @@ -27,7 +27,7 @@ #include "../../include/output/CMeshOutput.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" CMeshOutput::CMeshOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { diff --git a/SU2_CFD/src/output/COutput.cpp b/SU2_CFD/src/output/COutput.cpp index b7992e998ff9..16e199931b75 100644 --- a/SU2_CFD/src/output/COutput.cpp +++ b/SU2_CFD/src/output/COutput.cpp @@ -41,7 +41,7 @@ #include "../../include/output/filewriter/CSU2MeshFileWriter.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" COutput::COutput(CConfig *config, unsigned short nDim, bool fem_output): femOutput(fem_output) { diff --git a/SU2_CFD/src/output/filewriter/CFVMDataSorter.cpp b/SU2_CFD/src/output/filewriter/CFVMDataSorter.cpp index 5776b811e090..3b4c4897dd01 100644 --- a/SU2_CFD/src/output/filewriter/CFVMDataSorter.cpp +++ b/SU2_CFD/src/output/filewriter/CFVMDataSorter.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2019, SU2 Contributors (cf. AUTHORS.md) @@ -26,7 +26,7 @@ */ #include "../../../include/output/filewriter/CFVMDataSorter.hpp" -#include "../../../../Common/include/geometry_structure.hpp" +#include "../../../../Common/include/geometry/CGeometry.hpp" CFVMDataSorter::CFVMDataSorter(CConfig *config, CGeometry *geometry, unsigned short nFields) : CParallelDataSorter(config, nFields){ diff --git a/SU2_CFD/src/output/filewriter/CSurfaceFVMDataSorter.cpp b/SU2_CFD/src/output/filewriter/CSurfaceFVMDataSorter.cpp index ab98595e79e9..9c775de1f2f0 100644 --- a/SU2_CFD/src/output/filewriter/CSurfaceFVMDataSorter.cpp +++ b/SU2_CFD/src/output/filewriter/CSurfaceFVMDataSorter.cpp @@ -6,7 +6,7 @@ * * SU2 Project Website: https://su2code.github.io * - * The SU2 Project is maintained by the SU2 Foundation + * The SU2 Project is maintained by the SU2 Foundation * (http://su2foundation.org) * * Copyright 2012-2019, SU2 Contributors (cf. AUTHORS.md) @@ -26,7 +26,8 @@ */ #include "../../../include/output/filewriter/CSurfaceFVMDataSorter.hpp" -#include "../../../../Common/include/geometry_structure.hpp" +#include "../../../../Common/include/geometry/CGeometry.hpp" + CSurfaceFVMDataSorter::CSurfaceFVMDataSorter(CConfig *config, CGeometry *geometry, unsigned short nFields, CFVMDataSorter* volume_sorter) : CParallelDataSorter(config, nFields){ diff --git a/SU2_CFD/src/output/output_physics.cpp b/SU2_CFD/src/output/output_physics.cpp index 03186d6158ab..67e6a0707409 100644 --- a/SU2_CFD/src/output/output_physics.cpp +++ b/SU2_CFD/src/output/output_physics.cpp @@ -28,7 +28,7 @@ #include "../../include/output/COutputLegacy.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" void COutputLegacy::ComputeTurboPerformance(CSolver *solver_container, CGeometry *geometry, CConfig *config) { diff --git a/SU2_CFD/src/output/output_structure_legacy.cpp b/SU2_CFD/src/output/output_structure_legacy.cpp index f43474c77b76..824cb1c6c504 100644 --- a/SU2_CFD/src/output/output_structure_legacy.cpp +++ b/SU2_CFD/src/output/output_structure_legacy.cpp @@ -28,7 +28,7 @@ #include "../../include/output/COutputLegacy.hpp" -#include "../../../Common/include/geometry_structure.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solver_structure.hpp" COutputLegacy::COutputLegacy(CConfig *config) { @@ -4326,7 +4326,7 @@ void COutputLegacy::DeallocateSolution(CConfig *config, CGeometry *geometry) { } void COutputLegacy::SetConvHistory_Header(ofstream *ConvHist_file, CConfig *config, unsigned short val_iZone, unsigned short val_iInst) { - char cstr[200], buffer[50], turb_resid[1000], adj_turb_resid[1000]; + char cstr[200], turb_resid[1000], adj_turb_resid[1000]; unsigned short iMarker_Monitoring; string Monitoring_Tag, monitoring_coeff, aeroelastic_coeff, turbo_coeff; @@ -11823,7 +11823,7 @@ void COutputLegacy::SpecialOutput_Turbo(CSolver *****solver, CGeometry ****geome unsigned short iDim, iSpan; unsigned long iExtIter = config[val_iZone]->GetInnerIter(); - su2double* SpanWiseValuesIn, *SpanWiseValuesOut; + const su2double* SpanWiseValuesIn, *SpanWiseValuesOut; ofstream myfile; string spanwise_performance_filename; diff --git a/SU2_CFD/src/solver_direct_mean.cpp b/SU2_CFD/src/solver_direct_mean.cpp index 69acc291087c..38ea6fb6fe24 100644 --- a/SU2_CFD/src/solver_direct_mean.cpp +++ b/SU2_CFD/src/solver_direct_mean.cpp @@ -9623,7 +9623,7 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, su2double relfacFouCfg = config->GetGiles_RelaxFactorFourier(Marker_Tag); su2double *Normal; su2double TwoPiThetaFreq_Pitch, pitch,theta; - su2double *SpanWiseValues = NULL; + const su2double *SpanWiseValues = NULL; su2double spanPercent, extrarelfacAvg = 0.0, deltaSpan = 0.0, relfacAvg, relfacFou, coeffrelfacAvg = 0.0; unsigned short Turbo_Flag; @@ -12939,7 +12939,8 @@ void CEulerSolver::PreprocessAverage(CSolver **solver, CGeometry *geometry, CCon Area, TotalArea, TotalAreaPressure, TotalAreaDensity, *TotalAreaVelocity, *UnitNormal, *TurboNormal; string Marker_Tag, Monitoring_Tag; unsigned short iZone = config->GetiZone(); - su2double *AverageTurboNormal, VelSq; + const su2double *AverageTurboNormal; + su2double VelSq; /*-- Variables declaration and allocation ---*/ Velocity = new su2double[nDim]; @@ -13116,7 +13117,8 @@ void CEulerSolver::TurboAverageProcess(CSolver **solver, CGeometry *geometry, CC string Marker_Tag, Monitoring_Tag; su2double val_init_pressure; unsigned short iZone = config->GetiZone(); - su2double TotalDensity, TotalPressure, *TotalVelocity, *AverageTurboNormal, *TotalFluxes; + su2double TotalDensity, TotalPressure, *TotalVelocity, *TotalFluxes; + const su2double *AverageTurboNormal; su2double TotalNu, TotalOmega, TotalKine, TotalMassNu, TotalMassOmega, TotalMassKine, TotalAreaNu, TotalAreaOmega, TotalAreaKine; su2double Nu, Kine, Omega; su2double MachTest, soundSpeed; @@ -13732,9 +13734,8 @@ void CEulerSolver::TurboAverageProcess(CSolver **solver, CGeometry *geometry, CC } -void CEulerSolver::MixedOut_Average (CConfig *config, su2double val_init_pressure, su2double *val_Averaged_Flux, su2double *val_normal, - su2double& pressure_mix, su2double& density_mix) { - +void CEulerSolver::MixedOut_Average (CConfig *config, su2double val_init_pressure, const su2double *val_Averaged_Flux, + const su2double *val_normal, su2double& pressure_mix, su2double& density_mix) { su2double dx, f, df, resdl = 1.0E+05; unsigned short iter = 0, iDim; diff --git a/SU2_CFD/src/solver_direct_mean_inc.cpp b/SU2_CFD/src/solver_direct_mean_inc.cpp index 41296b4b5912..42f73a564b5e 100644 --- a/SU2_CFD/src/solver_direct_mean_inc.cpp +++ b/SU2_CFD/src/solver_direct_mean_inc.cpp @@ -7313,9 +7313,9 @@ void CIncNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container /*--- Compute gradient for MUSCL reconstruction. ---*/ -if (config->GetReconstructionGradientRequired() && (iMesh == MESH_0)) { - if (config->GetKind_Gradient_Method_Recon() == GREEN_GAUSS) - SetPrimitive_Gradient_GG(geometry, config, true); + if (config->GetReconstructionGradientRequired() && (iMesh == MESH_0)) { + if (config->GetKind_Gradient_Method_Recon() == GREEN_GAUSS) + SetPrimitive_Gradient_GG(geometry, config, true); if (config->GetKind_Gradient_Method_Recon() == LEAST_SQUARES) SetPrimitive_Gradient_LS(geometry, config, true); if (config->GetKind_Gradient_Method_Recon() == WEIGHTED_LEAST_SQUARES) diff --git a/SU2_CFD/src/solver_structure.cpp b/SU2_CFD/src/solver_structure.cpp index fdeb0bde73f2..d24189e10760 100644 --- a/SU2_CFD/src/solver_structure.cpp +++ b/SU2_CFD/src/solver_structure.cpp @@ -5038,183 +5038,179 @@ void CSolver::LoadInletProfile(CGeometry **geometry, if (dual_time || time_stepping) profile_filename = config->GetUnsteady_FileName(profile_filename, val_iter, ".dat"); - /*--- Read the profile data from an ASCII file. ---*/ + /*--- Read the profile data from an ASCII file. ---*/ - CMarkerProfileReaderFVM profileReader(geometry[MESH_0], config, profile_filename, KIND_MARKER, nCol_InletFile); + CMarkerProfileReaderFVM profileReader(geometry[MESH_0], config, profile_filename, KIND_MARKER, nCol_InletFile); - /*--- Load data from the restart into correct containers. ---*/ + /*--- Load data from the restart into correct containers. ---*/ - Marker_Counter = 0; - - unsigned short global_failure = 0, local_failure = 0; - ostringstream error_msg; + Marker_Counter = 0; + + unsigned short global_failure = 0, local_failure = 0; + ostringstream error_msg; - const su2double tolerance = config->GetInlet_Profile_Matching_Tolerance(); + const su2double tolerance = config->GetInlet_Profile_Matching_Tolerance(); - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == KIND_MARKER) { - - /*--- Get tag in order to identify the correct inlet data. ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == KIND_MARKER) { - Marker_Tag = config->GetMarker_All_TagBound(iMarker); + /*--- Get tag in order to identify the correct inlet data. ---*/ - for (jMarker = 0; jMarker < profileReader.GetNumberOfProfiles(); jMarker++) { + Marker_Tag = config->GetMarker_All_TagBound(iMarker); - /*--- If we have found the matching marker string, continue. ---*/ + for (jMarker = 0; jMarker < profileReader.GetNumberOfProfiles(); jMarker++) { - if (profileReader.GetTagForProfile(jMarker) == Marker_Tag) { + /*--- If we have found the matching marker string, continue. ---*/ - /*--- Increment our counter for marker matches. ---*/ + if (profileReader.GetTagForProfile(jMarker) == Marker_Tag) { - Marker_Counter++; + /*--- Increment our counter for marker matches. ---*/ - /*--- Get data for this profile. ---*/ - - vector Inlet_Data = profileReader.GetDataForProfile(jMarker); - - unsigned short nColumns = profileReader.GetNumberOfColumnsInProfile(jMarker); + Marker_Counter++; - vector Inlet_Values(nColumns); - - /*--- Loop through the nodes on this marker. ---*/ + /*--- Get data for this profile. ---*/ + + vector Inlet_Data = profileReader.GetDataForProfile(jMarker); + + unsigned short nColumns = profileReader.GetNumberOfColumnsInProfile(jMarker); - for (iVertex = 0; iVertex < geometry[MESH_0]->nVertex[iMarker]; iVertex++) { + vector Inlet_Values(nColumns); + + /*--- Loop through the nodes on this marker. ---*/ - iPoint = geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); - Coord = geometry[MESH_0]->node[iPoint]->GetCoord(); - min_dist = 1e16; + for (iVertex = 0; iVertex < geometry[MESH_0]->nVertex[iMarker]; iVertex++) { - /*--- Find the distance to the closest point in our inlet profile data. ---*/ + iPoint = geometry[MESH_0]->vertex[iMarker][iVertex]->GetNode(); + Coord = geometry[MESH_0]->node[iPoint]->GetCoord(); + min_dist = 1e16; - for (iRow = 0; iRow < profileReader.GetNumberOfRowsInProfile(jMarker); iRow++) { + /*--- Find the distance to the closest point in our inlet profile data. ---*/ - /*--- Get the coords for this data point. ---*/ + for (iRow = 0; iRow < profileReader.GetNumberOfRowsInProfile(jMarker); iRow++) { - index = iRow*nColumns; + /*--- Get the coords for this data point. ---*/ - dist = 0.0; - for (unsigned short iDim = 0; iDim < nDim; iDim++) - dist += pow(Inlet_Data[index+iDim] - Coord[iDim], 2); - dist = sqrt(dist); + index = iRow*nColumns; - /*--- Check is this is the closest point and store data if so. ---*/ + dist = 0.0; + for (unsigned short iDim = 0; iDim < nDim; iDim++) + dist += pow(Inlet_Data[index+iDim] - Coord[iDim], 2); + dist = sqrt(dist); - if (dist < min_dist) { - min_dist = dist; - for (iVar = 0; iVar < nColumns; iVar++) - Inlet_Values[iVar] = Inlet_Data[index+iVar]; - } + /*--- Check is this is the closest point and store data if so. ---*/ + if (dist < min_dist) { + min_dist = dist; + for (iVar = 0; iVar < nColumns; iVar++) + Inlet_Values[iVar] = Inlet_Data[index+iVar]; } - /*--- If the diff is less than the tolerance, match the two. - We could modify this to simply use the nearest neighbor, or - eventually add something more elaborate here for interpolation. ---*/ - - if (min_dist < tolerance) { - - solver[MESH_0][KIND_SOLVER]->SetInletAtVertex(Inlet_Values.data(), iMarker, iVertex); - - } else { + } - unsigned long GlobalIndex = geometry[MESH_0]->node[iPoint]->GetGlobalIndex(); - cout << "WARNING: Did not find a match between the points in the inlet file" << endl; - cout << "and point " << GlobalIndex; - cout << std::scientific; - cout << " at location: [" << Coord[0] << ", " << Coord[1]; - if (nDim ==3) error_msg << ", " << Coord[2]; - cout << "]" << endl; - cout << "Distance to closest point: " << min_dist << endl; - cout << "Current tolerance: " << tolerance << endl; - cout << endl; - cout << "You can widen the tolerance for point matching by changing the value" << endl; - cout << "of the option INLET_MATCHING_TOLERANCE in your *.cfg file." << endl; - local_failure++; - break; + /*--- If the diff is less than the tolerance, match the two. + We could modify this to simply use the nearest neighbor, or + eventually add something more elaborate here for interpolation. ---*/ + + if (min_dist < tolerance) { + + solver[MESH_0][KIND_SOLVER]->SetInletAtVertex(Inlet_Values.data(), iMarker, iVertex); + + } else { + + unsigned long GlobalIndex = geometry[MESH_0]->node[iPoint]->GetGlobalIndex(); + cout << "WARNING: Did not find a match between the points in the inlet file" << endl; + cout << "and point " << GlobalIndex; + cout << std::scientific; + cout << " at location: [" << Coord[0] << ", " << Coord[1]; + if (nDim ==3) error_msg << ", " << Coord[2]; + cout << "]" << endl; + cout << "Distance to closest point: " << min_dist << endl; + cout << "Current tolerance: " << tolerance << endl; + cout << endl; + cout << "You can widen the tolerance for point matching by changing the value" << endl; + cout << "of the option INLET_MATCHING_TOLERANCE in your *.cfg file." << endl; + local_failure++; + break; - } } } } } - - if (local_failure > 0) break; } -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&local_failure, &global_failure, 1, MPI_UNSIGNED_SHORT, - MPI_SUM, MPI_COMM_WORLD); -#else - global_failure = local_failure; -#endif + if (local_failure > 0) break; + } - if (global_failure > 0) { - SU2_MPI::Error(string("Prescribed inlet data does not match markers within tolerance."), CURRENT_FUNCTION); - } + SU2_MPI::Allreduce(&local_failure, &global_failure, 1, MPI_UNSIGNED_SHORT, MPI_SUM, MPI_COMM_WORLD); - /*--- Copy the inlet data down to the coarse levels if multigrid is active. - Here, we use a face area-averaging to restrict the values. ---*/ + if (global_failure > 0) { + SU2_MPI::Error("Prescribed inlet data does not match markers within tolerance.", CURRENT_FUNCTION); + } - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - for (iMarker=0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == KIND_MARKER) { + /*--- Copy the inlet data down to the coarse levels if multigrid is active. + Here, we use a face area-averaging to restrict the values. ---*/ - Marker_Tag = config->GetMarker_All_TagBound(iMarker); - - /* Check the number of columns and allocate temp array. */ - - unsigned short nColumns; - for (jMarker = 0; jMarker < profileReader.GetNumberOfProfiles(); jMarker++) { - if (profileReader.GetTagForProfile(jMarker) == Marker_Tag) { - nColumns = profileReader.GetNumberOfColumnsInProfile(jMarker); - } + for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { + for (iMarker=0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == KIND_MARKER) { + + Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + /* Check the number of columns and allocate temp array. */ + + unsigned short nColumns = 0; + for (jMarker = 0; jMarker < profileReader.GetNumberOfProfiles(); jMarker++) { + if (profileReader.GetTagForProfile(jMarker) == Marker_Tag) { + nColumns = profileReader.GetNumberOfColumnsInProfile(jMarker); } - vector Inlet_Values(nColumns); - vector Inlet_Fine(nColumns); - - /*--- Loop through the nodes on this marker. ---*/ + } + vector Inlet_Values(nColumns); + vector Inlet_Fine(nColumns); + + /*--- Loop through the nodes on this marker. ---*/ - for (iVertex = 0; iVertex < geometry[iMesh]->nVertex[iMarker]; iVertex++) { + for (iVertex = 0; iVertex < geometry[iMesh]->nVertex[iMarker]; iVertex++) { - /*--- Get the coarse mesh point and compute the boundary area. ---*/ + /*--- Get the coarse mesh point and compute the boundary area. ---*/ - iPoint = geometry[iMesh]->vertex[iMarker][iVertex]->GetNode(); - geometry[iMesh]->vertex[iMarker][iVertex]->GetNormal(Normal); - Area_Parent = 0.0; - for (iDim = 0; iDim < nDim; iDim++) Area_Parent += Normal[iDim]*Normal[iDim]; - Area_Parent = sqrt(Area_Parent); + iPoint = geometry[iMesh]->vertex[iMarker][iVertex]->GetNode(); + geometry[iMesh]->vertex[iMarker][iVertex]->GetNormal(Normal); + Area_Parent = 0.0; + for (iDim = 0; iDim < nDim; iDim++) Area_Parent += Normal[iDim]*Normal[iDim]; + Area_Parent = sqrt(Area_Parent); - /*--- Reset the values for the coarse point. ---*/ + /*--- Reset the values for the coarse point. ---*/ - for (iVar = 0; iVar < nColumns; iVar++) Inlet_Values[iVar] = 0.0; + for (iVar = 0; iVar < nColumns; iVar++) Inlet_Values[iVar] = 0.0; - /*-- Loop through the children and extract the inlet values - from those nodes that lie on the boundary as well as their - boundary area. We build a face area-averaged value for the - coarse point values from the fine grid points. Note that - children from the interior volume will not be included in - the averaging. ---*/ + /*-- Loop through the children and extract the inlet values + from those nodes that lie on the boundary as well as their + boundary area. We build a face area-averaged value for the + coarse point values from the fine grid points. Note that + children from the interior volume will not be included in + the averaging. ---*/ - for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { - Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); - for (iVar = 0; iVar < nColumns; iVar++) Inlet_Fine[iVar] = 0.0; - Area_Children = solver[iMesh-1][KIND_SOLVER]->GetInletAtVertex(Inlet_Fine.data(), Point_Fine, KIND_MARKER, Marker_Tag, geometry[iMesh-1], config); - for (iVar = 0; iVar < nColumns; iVar++) { - Inlet_Values[iVar] += Inlet_Fine[iVar]*Area_Children/Area_Parent; - } + for (iChildren = 0; iChildren < geometry[iMesh]->node[iPoint]->GetnChildren_CV(); iChildren++) { + Point_Fine = geometry[iMesh]->node[iPoint]->GetChildren_CV(iChildren); + for (iVar = 0; iVar < nColumns; iVar++) Inlet_Fine[iVar] = 0.0; + Area_Children = solver[iMesh-1][KIND_SOLVER]->GetInletAtVertex(Inlet_Fine.data(), Point_Fine, KIND_MARKER, + Marker_Tag, geometry[iMesh-1], config); + for (iVar = 0; iVar < nColumns; iVar++) { + Inlet_Values[iVar] += Inlet_Fine[iVar]*Area_Children/Area_Parent; } + } - /*--- Set the boundary area-averaged inlet values for the coarse point. ---*/ + /*--- Set the boundary area-averaged inlet values for the coarse point. ---*/ - solver[iMesh][KIND_SOLVER]->SetInletAtVertex(Inlet_Values.data(), iMarker, iVertex); + solver[iMesh][KIND_SOLVER]->SetInletAtVertex(Inlet_Values.data(), iMarker, iVertex); - } } } } - + } + delete [] Normal; - + } void CSolver::ComputeVertexTractions(CGeometry *geometry, CConfig *config){ diff --git a/SU2_DEF/include/SU2_DEF.hpp b/SU2_DEF/include/SU2_DEF.hpp index 5919aacea2db..596655e00c92 100644 --- a/SU2_DEF/include/SU2_DEF.hpp +++ b/SU2_DEF/include/SU2_DEF.hpp @@ -38,7 +38,7 @@ #include "../../SU2_CFD/include/solver_structure.hpp" #include "../../SU2_CFD/include/output/CMeshOutput.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../Common/include/config_structure.hpp" #include "../../Common/include/grid_movement_structure.hpp" diff --git a/SU2_DOT/include/SU2_DOT.hpp b/SU2_DOT/include/SU2_DOT.hpp index 8fe4653f3c66..09dfe1ab2647 100644 --- a/SU2_DOT/include/SU2_DOT.hpp +++ b/SU2_DOT/include/SU2_DOT.hpp @@ -36,7 +36,7 @@ #include #include -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../Common/include/fem_geometry_structure.hpp" #include "../../Common/include/config_structure.hpp" #include "../../Common/include/grid_movement_structure.hpp" diff --git a/SU2_GEO/include/SU2_GEO.hpp b/SU2_GEO/include/SU2_GEO.hpp index 18c76880dc01..28898bf79b13 100644 --- a/SU2_GEO/include/SU2_GEO.hpp +++ b/SU2_GEO/include/SU2_GEO.hpp @@ -36,7 +36,7 @@ #include #include -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../Common/include/config_structure.hpp" #include "../../Common/include/grid_movement_structure.hpp" diff --git a/SU2_MSH/include/SU2_MSH.hpp b/SU2_MSH/include/SU2_MSH.hpp index a6d88e5cc69c..22a57179bbe3 100644 --- a/SU2_MSH/include/SU2_MSH.hpp +++ b/SU2_MSH/include/SU2_MSH.hpp @@ -36,7 +36,7 @@ #include #include -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../Common/include/config_structure.hpp" #include "../../Common/include/grid_adaptation_structure.hpp" diff --git a/SU2_SOL/include/SU2_SOL.hpp b/SU2_SOL/include/SU2_SOL.hpp index 8bf3a85d9194..043ad6d7f547 100644 --- a/SU2_SOL/include/SU2_SOL.hpp +++ b/SU2_SOL/include/SU2_SOL.hpp @@ -35,7 +35,7 @@ #include "../../SU2_CFD/include/solver_structure.hpp" #include "../../SU2_CFD/include/output/CBaselineOutput.hpp" -#include "../../Common/include/geometry_structure.hpp" +#include "../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../Common/include/config_structure.hpp"