From 2fc2dd0e4c7b9716b46bd9bc7c5951cdd5f73b6a Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Sat, 9 Mar 2024 11:50:35 +0100 Subject: [PATCH 01/19] Added mesh deformation type as option in the config file. --- Common/include/CConfig.hpp | 7 +++++++ Common/include/option_structure.hpp | 13 +++++++++++++ Common/src/CConfig.cpp | 2 ++ 3 files changed, 22 insertions(+) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index c28c3aaef54..8503759ed42 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -652,6 +652,7 @@ class CConfig { su2double Deform_Tol_Factor; /*!< \brief Factor to multiply smallest volume for deform tolerance (0.001 default) */ su2double Deform_Coeff; /*!< \brief Deform coeffienct */ su2double Deform_Limit; /*!< \brief Deform limit */ + DEFORM_KIND Deform_Kind; /*!< \brief Type of mesh deformation */ unsigned short FFD_Continuity; /*!< \brief Surface continuity at the intersection with the FFD */ unsigned short FFD_CoordSystem; /*!< \brief Define the coordinates system */ su2double Deform_ElasticityMod, /*!< \brief Young's modulus for volume deformation stiffness model */ @@ -4375,6 +4376,12 @@ class CConfig { */ bool GetFFD_Symmetry_Plane(void) const { return FFD_Symmetry_Plane; } + /*! + * \brief Get the type of mesh deformation method. + * \return type of mesh deformation. + */ + DEFORM_KIND GetDeform_Kind(void) const { return Deform_Kind; } + /*! * \brief Get the kind of SU2 software component. * \return Kind of the SU2 software component. diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 7199a310193..662da7b3938 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -2642,6 +2642,19 @@ static const MapType Sobolev_Modus_Map = { MakePair("ONLY_GRADIENT", ENUM_SOBOLEV_MODUS::ONLY_GRAD) }; +/*! + * \brief Type of mesh deformation + */ +enum class DEFORM_KIND { + ELASTIC, /*!< \brief Linear elasticity method. */ + RBF /*!< \brief Radial basis function interpolation. */ +}; +static const MapType Deform_Kind_Map = { + MakePair("ELASTIC", DEFORM_KIND::ELASTIC) + MakePair("RBF", DEFORM_KIND::RBF) +}; + + #undef MakePair /* END_CONFIG_ENUMS */ diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 18da76556c4..5737c4700c6 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2375,6 +2375,8 @@ void CConfig::SetConfig_Options() { addDoubleOption("DEFORM_LINEAR_SOLVER_ERROR", Deform_Linear_Solver_Error, 1E-14); /* DESCRIPTION: Maximum number of iterations of the linear solver for the implicit formulation */ addUnsignedLongOption("DEFORM_LINEAR_SOLVER_ITER", Deform_Linear_Solver_Iter, 1000); + /* DESCRIPTION: Type of mesh deformation */ + addEnumOption("DEFORM_KIND", Deform_Kind, Deform_Kind_Map, DEFORM_KIND::ELASTIC); /*!\par CONFIG_CATEGORY: FEM flow solver definition \ingroup Config*/ /*--- Options related to the finite element flow solver---*/ From 2ff6718fcbb2e0f595ff982be9437ddfc03b06b5 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Tue, 12 Mar 2024 22:11:23 +0100 Subject: [PATCH 02/19] WIP RBF mesh deformation --- .../grid_movement/CLinearElasticity.hpp | 243 +++ .../CRadialBasisFunctionInterpolation.hpp | 144 ++ .../CRadialBasisFunctionNode.hpp | 67 + .../grid_movement/CVolumetricMovement.hpp | 199 +-- .../CVolumetricMovementFactory.hpp | 42 + .../src/grid_movement/CLinearElasticity.cpp | 1478 +++++++++++++++++ .../CRadialBasisFunctionInterpolation.cpp | 234 +++ .../CRadialBasisFunctionNode.cpp | 34 + .../src/grid_movement/CVolumetricMovement.cpp | 1454 +--------------- .../CVolumetricMovementFactory.cpp | 50 + Common/src/grid_movement/meson.build | 6 +- SU2_CFD/src/drivers/CDriver.cpp | 5 +- SU2_DEF/src/drivers/CDeformationDriver.cpp | 6 +- .../src/drivers/CDiscAdjDeformationDriver.cpp | 5 +- 14 files changed, 2325 insertions(+), 1642 deletions(-) create mode 100644 Common/include/grid_movement/CLinearElasticity.hpp create mode 100644 Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp create mode 100644 Common/include/grid_movement/CRadialBasisFunctionNode.hpp create mode 100644 Common/include/grid_movement/CVolumetricMovementFactory.hpp create mode 100644 Common/src/grid_movement/CLinearElasticity.cpp create mode 100644 Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp create mode 100644 Common/src/grid_movement/CRadialBasisFunctionNode.cpp create mode 100644 Common/src/grid_movement/CVolumetricMovementFactory.cpp diff --git a/Common/include/grid_movement/CLinearElasticity.hpp b/Common/include/grid_movement/CLinearElasticity.hpp new file mode 100644 index 00000000000..02ad40c8181 --- /dev/null +++ b/Common/include/grid_movement/CLinearElasticity.hpp @@ -0,0 +1,243 @@ +/*! + * \file CLinearElasticity.hpp + * \brief Headers of the CLinearElasticity class. + * \author F. Palacios, A. Bueno, T. Economon, S. Padron. + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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 "CVolumetricMovement.hpp" +#include "../linear_algebra/CSysMatrix.hpp" +#include "../linear_algebra/CSysVector.hpp" +#include "../linear_algebra/CSysSolve.hpp" + +/*! + * \class CLinearElasticity + * \brief Class for moving the volumetric numerical grid using the linear elasticity analogy. + * \author F. Palacios, A. Bueno, T. Economon, S. Padron. + */ + +class CLinearElasticity final: public CVolumetricMovement{ + protected: + unsigned short nVar; /*!< \brief Number of variables. */ + + unsigned long nPoint; /*!< \brief Number of points. */ + unsigned long nPointDomain; /*!< \brief Number of points in the domain. */ + + unsigned long nIterMesh; /*!< \brief Number of iterations in the mesh update. +*/ + + + #ifndef CODI_FORWARD_TYPE + CSysMatrix StiffMatrix; /*!< \brief Stiffness matrix of the elasticity problem. */ + CSysSolve System; /*!< \brief Linear solver/smoother. */ +#else + CSysMatrix StiffMatrix; + CSysSolve System; +#endif + CSysVector LinSysSol; + CSysVector LinSysRes; + + public: + /*! + * \brief Constructor of the class. + */ + CLinearElasticity(CGeometry* geometry, CConfig* config); + + //TODO add deconstructor + + /*! + * \brief Grid deformation using the spring analogy method. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] UpdateGeo - Update geometry. + * \param[in] Derivative - Compute the derivative (disabled by default). Does not actually deform the grid if enabled. + */ + void SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, + bool ForwardProjectionDerivative); + + /*! + * \brief Update the value of the coordinates after the grid movement. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void UpdateGridCoord(CGeometry* geometry, CConfig* config); + + /*! + * \brief Update the derivatives of the coordinates after the grid movement. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void UpdateGridCoord_Derivatives(CGeometry* geometry, CConfig* config, bool ForwardProjectionDerivative); + + /*! + * \brief Compute the minimum distance to the nearest solid surface. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void ComputeSolid_Wall_Distance(CGeometry* geometry, CConfig* config, su2double& MinDistance, + su2double& MaxDistance) const; + + /*! + * \brief Compute the stiffness matrix for grid deformation using spring analogy. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \return Value of the length of the smallest edge of the grid. + */ + su2double SetFEAMethodContributions_Elem(CGeometry* geometry, CConfig* config); + + /*! + * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. + * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. + * \param[in] PointCorners - Index values for element corners + * \param[in] nNodes - Number of nodes defining the element. + * \param[in] scale + */ + void SetFEA_StiffMatrix2D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, + unsigned long PointCorners[8], su2double CoordCorners[8][3], + unsigned short nNodes, su2double ElemVolume, su2double ElemDistance) ; + + /*! + * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. + * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. + * \param[in] PointCorners - Index values for element corners + * \param[in] nNodes - Number of nodes defining the element. + * \param[in] scale + */ + void SetFEA_StiffMatrix3D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, + unsigned long PointCorners[8], su2double CoordCorners[8][3], + unsigned short nNodes, su2double ElemVolume, su2double ElemDistance); + + /*! + * \brief Add the stiffness matrix for a 2-D triangular element to the global stiffness matrix for the entire mesh + * (node-based). \param[in] geometry - Geometrical definition of the problem. \param[in] StiffMatrix_Elem - Element + * stiffness matrix to be filled. \param[in] PointCorners - Index values for element corners \param[in] nNodes - + * Number of nodes defining the element. + */ + void AddFEA_StiffMatrix(CGeometry* geometry, su2double** StiffMatrix_Elem, + unsigned long PointCorners[8], unsigned short nNodes); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Zeta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Zeta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Zeta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] Zeta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]); + + /*! + * \brief Shape functions and derivative of the shape functions + * \param[in] Xi - Local coordinates. + * \param[in] Eta - Local coordinates. + * \param[in] CoordCorners - Coordiantes of the corners. + * \param[in] DShapeFunction - Shape function information + */ + su2double ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]); + + /*! + * \brief Check the domain points vertex that are going to be moved. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetDomainDisplacements(CGeometry* geometry, CConfig* config); + + /*! + * \brief Check the boundary vertex that are going to be moved. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetBoundaryDisplacements(CGeometry* geometry, CConfig* config); + + /*! + * \brief Set the derivatives of the boundary nodes. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetBoundaryDerivatives(CGeometry* geometry, CConfig* config, bool ForwardProjectionDerivative); + + /*! + * \brief Store the number of iterations when moving the mesh. + * \param[in] val_nIterMesh - Number of iterations. + */ + inline void Set_nIterMesh(unsigned long val_nIterMesh) { nIterMesh = val_nIterMesh; } + + /*! + * \brief Retrieve the number of iterations when moving the mesh. + * \param[out] Number of iterations. + */ + inline unsigned long Get_nIterMesh() const { return nIterMesh; } +}; + + diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp new file mode 100644 index 00000000000..dde59f291dc --- /dev/null +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -0,0 +1,144 @@ +/*! + * \file CRadialBasisFunctionInterpolation.hpp + * \brief Headers of the CRadialBasisFunctionInterpolation class. + * \author F. van Steen + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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 "CVolumetricMovement.hpp" +#include "CRadialBasisFunctionNode.hpp" +#include "../../include/toolboxes/CSymmetricMatrix.hpp" + +/*! + * \class CLinearElasticity + * \brief Class for moving the volumetric numerical grid using Radial Basis Function interpolation. + * \author F. van Steen + */ + +class CRadialBasisFunctionInterpolation : public CVolumetricMovement { +protected: + + vector boundaryNodes; /*!< \brief Vector with boundary nodes.*/ + vector internalNodes; /*!< \brief Vector with internal nodes.*/ + unsigned long nBoundaryNodes, /*!< \brief Number of boundary nodes*/ + nInternalNodes; /*!< \brief Number of internal nodes*/ + + vector* controlNodes; /*!< \brief Vector with control nodes*/ + + vector deformationVector; /*!< \brief Deformation vector.*/ + vector coefficients; /*!< \brief Control node interpolation coefficients.*/ + CSymmetricMatrix interpMat; /*!< \brief Interpolation matrix.*/ + + RADIAL_BASIS kindRBF; /*!< \brief Type of Radial Basis Function.*/ + su2double radius; /*!< \brief Support radius of compact Radial Basis Function.*/ + +public: + // TODO make destructor + + /*! + * \brief Constructor of the class. + */ + CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config); + + // /*! + // * \brief Destructor of the class. + // */ + // ~CGridRadialBasisFunction(void) override; + + /*! + * \brief Grid deformation using the spring analogy method. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] UpdateGeo - Update geometry. + * \param[in] Derivative - Compute the derivative (disabled by default). Does not actually deform the grid if enabled. + */ + void SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, + bool ForwardProjectionDerivative); + + /*! + * \brief Obtaining the interpolation coefficients based on displacement of the control nodes. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] iNonlinear_Iter - Surface deformation step. + */ + void GetInterpolationCoefficients(CGeometry* geometry, CConfig* config, unsigned long iNonlinear_Iter); + + /*! + * \brief Compute the interpolation matrix with Radial Basis Function evaluations. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetInterpolationMatrix(CGeometry* geometry, CConfig* config); + + /*! + * \brief Build the deformation vector with surface displacements of the control nodes. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetDeformationVector(CGeometry* geometry, CConfig* config); + + /*! + * \brief Selecting unique set of control nodes based on marker information. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void SetControlNodes(CGeometry* geometry, CConfig* config); + + /*! + * \brief Selecting internal nodes for the volumetric deformation. + * \param[in] geometry - Geometrical definition of the problem. + */ + void SetInternalNodes(CGeometry* geometry); + + /*! + * \brief Solving of the Radial Basis Function interpolation system, yielding the interpolation coefficients + */ + void SolveRBF_System(void); + + + /*! + * \brief Updating the grid coordinates. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + */ + void UpdateGridCoord(CGeometry* geometry, CConfig* config); + + /*! + * \brief Custom comparison function, for sorting the CRadialBasisFunctionNode objects based on their index. + * \param[in] a - First considered Radial Basis Function Node. + * \param[in] b - second considered Radial Basis Function Node. + */ + inline static bool Compare(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ + return a->GetIndex() < b->GetIndex(); + } + + /*! + * \brief Custom equality function, for obtaining a unique set of CRadialBasisFunctionNode objects. + * \param[in] a - First considered Radial Basis Function Node. + * \param[in] b - second considered Radial Basis Function Node. + */ + inline static bool Equal(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ + return a->GetIndex() == b->GetIndex(); + } +}; \ No newline at end of file diff --git a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp new file mode 100644 index 00000000000..989a9cd35c6 --- /dev/null +++ b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp @@ -0,0 +1,67 @@ +/*! + * \file CRadialBasisFunctionNode.hpp + * \brief Declaration of the RBF node class that stores nodal information for the RBF interpolation. + * \author F. van Steen + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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 "../../../Common/include/geometry/CGeometry.hpp" + +/*! + * \class CRadialBasisFunctionNode + * \brief Class for defining a Radial Basis Function Node + * \author F. van Steen + */ + +class CRadialBasisFunctionNode{ + protected: + unsigned long idx; /*!< \brief Global index. */ + unsigned short marker_idx; /*!< \brief Marker index. */ + unsigned long vertex_idx; /*!< \brief Vertex index. */ + + + public: + + /*! + * \brief Constructor of the class. + */ + CRadialBasisFunctionNode(CGeometry* geometry, unsigned short marker_val, unsigned long vertex_val); + + /*! + * \brief Returns global index. + */ + inline unsigned long GetIndex(void){return idx;} + + /*! + * \brief Returns vertex index. + */ + inline unsigned long GetVertex(void){return vertex_idx;} + + /*! + * \brief Returns marker index. + */ + inline unsigned short GetMarker(void){return marker_idx;} + +}; \ No newline at end of file diff --git a/Common/include/grid_movement/CVolumetricMovement.hpp b/Common/include/grid_movement/CVolumetricMovement.hpp index 95f324bb902..dcb787894fe 100644 --- a/Common/include/grid_movement/CVolumetricMovement.hpp +++ b/Common/include/grid_movement/CVolumetricMovement.hpp @@ -28,9 +28,7 @@ #pragma once #include "CGridMovement.hpp" -#include "../linear_algebra/CSysMatrix.hpp" -#include "../linear_algebra/CSysVector.hpp" -#include "../linear_algebra/CSysSolve.hpp" + /*! * \class CVolumetricMovement @@ -39,23 +37,7 @@ */ class CVolumetricMovement : public CGridMovement { protected: - unsigned short nDim; /*!< \brief Number of dimensions. */ - unsigned short nVar; /*!< \brief Number of variables. */ - - unsigned long nPoint; /*!< \brief Number of points. */ - unsigned long nPointDomain; /*!< \brief Number of points in the domain. */ - - unsigned long nIterMesh; /*!< \brief Number of iterations in the mesh update. +*/ - -#ifndef CODI_FORWARD_TYPE - CSysMatrix StiffMatrix; /*!< \brief Stiffness matrix of the elasticity problem. */ - CSysSolve System; /*!< \brief Linear solver/smoother. */ -#else - CSysMatrix StiffMatrix; - CSysSolve System; -#endif - CSysVector LinSysSol; - CSysVector LinSysRes; + unsigned short nDim; /*!< \brief Number of dimensions. */ public: /*! @@ -64,22 +46,16 @@ class CVolumetricMovement : public CGridMovement { CVolumetricMovement(void); /*! - * \brief Constructor of the class. - */ - CVolumetricMovement(CGeometry* geometry, CConfig* config); + * \brief Constructor of the Class. + */ + + CVolumetricMovement(CGeometry* geometry); /*! * \brief Destructor of the class. */ ~CVolumetricMovement(void) override; - /*! - * \brief Update the value of the coordinates after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateGridCoord(CGeometry* geometry, CConfig* config); - /*! * \brief Update the dual grid after the grid movement (edges and control volumes). * \param[in] geometry - Geometrical definition of the problem. @@ -94,106 +70,6 @@ class CVolumetricMovement : public CGridMovement { */ void UpdateMultiGrid(CGeometry** geometry, CConfig* config); - /*! - * \brief Compute the stiffness matrix for grid deformation using spring analogy. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \return Value of the length of the smallest edge of the grid. - */ - su2double SetFEAMethodContributions_Elem(CGeometry* geometry, CConfig* config); - - /*! - * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. - * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. - * \param[in] PointCorners - Index values for element corners - * \param[in] nNodes - Number of nodes defining the element. - * \param[in] scale - */ - void SetFEA_StiffMatrix3D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, - unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, - su2double ElemVolume, su2double ElemDistance); - - /*! - * \brief Build the stiffness matrix for a 3-D hexahedron element. The result will be placed in StiffMatrix_Elem. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - * \param[in] StiffMatrix_Elem - Element stiffness matrix to be filled. - * \param[in] CoordCorners - Index value for Node 1 of the current hexahedron. - * \param[in] PointCorners - Index values for element corners - * \param[in] nNodes - Number of nodes defining the element. - * \param[in] scale - */ - void SetFEA_StiffMatrix2D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, - unsigned long PointCorners[8], su2double CoordCorners[8][3], unsigned short nNodes, - su2double ElemVolume, su2double ElemDistance); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Zeta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Zeta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Zeta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] Zeta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]); - - /*! - * \brief Shape functions and derivative of the shape functions - * \param[in] Xi - Local coordinates. - * \param[in] Eta - Local coordinates. - * \param[in] CoordCorners - Coordiantes of the corners. - * \param[in] DShapeFunction - Shape function information - */ - su2double ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]); - /*! * \brief Compute the shape functions for hexahedron * \param[in] CoordCorners - coordinates of the cornes of the hexahedron. @@ -230,15 +106,6 @@ class CVolumetricMovement : public CGridMovement { */ su2double GetQuadrilateral_Area(su2double CoordCorners[8][3]) const; - /*! - * \brief Add the stiffness matrix for a 2-D triangular element to the global stiffness matrix for the entire mesh - * (node-based). \param[in] geometry - Geometrical definition of the problem. \param[in] StiffMatrix_Elem - Element - * stiffness matrix to be filled. \param[in] PointCorners - Index values for element corners \param[in] nNodes - - * Number of nodes defining the element. - */ - void AddFEA_StiffMatrix(CGeometry* geometry, su2double** StiffMatrix_Elem, unsigned long PointCorners[8], - unsigned short nNodes); - /*! * \brief Check for negative volumes (all elements) after performing grid deformation. * \param[in] geometry - Geometrical definition of the problem. @@ -253,29 +120,7 @@ class CVolumetricMovement : public CGridMovement { * \param[in] Screen_Output - determines if text is written to screen */ void ComputenNonconvexElements(CGeometry* geometry, bool Screen_Output); - - /*! - * \brief Compute the minimum distance to the nearest solid surface. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void ComputeSolid_Wall_Distance(CGeometry* geometry, CConfig* config, su2double& MinDistance, - su2double& MaxDistance) const; - - /*! - * \brief Check the boundary vertex that are going to be moved. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetBoundaryDisplacements(CGeometry* geometry, CConfig* config); - - /*! - * \brief Check the domain points vertex that are going to be moved. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetDomainDisplacements(CGeometry* geometry, CConfig* config); - + /*! * \brief Unsteady grid movement using rigid mesh rotation. * \param[in] geometry - Geometrical definition of the problem. @@ -343,8 +188,8 @@ class CVolumetricMovement : public CGridMovement { * \param[in] UpdateGeo - Update geometry. * \param[in] Derivative - Compute the derivative (disabled by default). Does not actually deform the grid if enabled. */ - void SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative = false, - bool ForwardProjectionDerivative = false); + inline virtual void SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative = false, + bool ForwardProjectionDerivative = false){}; /*! * \brief Grid deformation using the spring analogy method. @@ -356,32 +201,6 @@ class CVolumetricMovement : public CGridMovement { inline virtual void SetVolume_Deformation_Elas(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool screen_output, bool Derivative = false) {} - /*! - * \brief Set the derivatives of the boundary nodes. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void SetBoundaryDerivatives(CGeometry* geometry, CConfig* config, bool ForwardProjectionDerivative); - - /*! - * \brief Update the derivatives of the coordinates after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateGridCoord_Derivatives(CGeometry* geometry, CConfig* config, bool ForwardProjectionDerivative); - - /*! - * \brief Store the number of iterations when moving the mesh. - * \param[in] val_nIterMesh - Number of iterations. - */ - inline void Set_nIterMesh(unsigned long val_nIterMesh) { nIterMesh = val_nIterMesh; } - - /*! - * \brief Retrieve the number of iterations when moving the mesh. - * \param[out] Number of iterations. - */ - inline unsigned long Get_nIterMesh() const { return nIterMesh; } - /*! * \brief Set the boundary dependencies in the mesh side of the problem * \param[in] geometry - Geometrical definition of the problem. diff --git a/Common/include/grid_movement/CVolumetricMovementFactory.hpp b/Common/include/grid_movement/CVolumetricMovementFactory.hpp new file mode 100644 index 00000000000..b917e57b57f --- /dev/null +++ b/Common/include/grid_movement/CVolumetricMovementFactory.hpp @@ -0,0 +1,42 @@ +/*! + * \file CVolumetricMovementFactory.hpp + * \brief Factory to generate volumetric mover objects. + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2024, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +class CConfig; +class CGeometry; +class CVolumetricMovement; + +namespace CVolumetricMovementFactory { +/*! + * \brief Factory method for CVolumetricMovement objects. + * \param[in] geometry_container - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \return Pointer to volumetric moever on the heap, caller is responsible for deletion. + */ + + CVolumetricMovement* CreateCVolumetricMovement(CGeometry* geometry, CConfig* config); +} \ No newline at end of file diff --git a/Common/src/grid_movement/CLinearElasticity.cpp b/Common/src/grid_movement/CLinearElasticity.cpp new file mode 100644 index 00000000000..abb355a8c85 --- /dev/null +++ b/Common/src/grid_movement/CLinearElasticity.cpp @@ -0,0 +1,1478 @@ +/*! + * \file CLinearElasticity.cpp + * \brief Subroutines for moving mesh volume elements using the linear elasticity analogy + * \author F. Palacios, T. Economon, S. Padron + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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/grid_movement/CLinearElasticity.hpp" +#include "../../include/adt/CADTPointsOnlyClass.hpp" + +CLinearElasticity::CLinearElasticity(CGeometry* geometry, CConfig* config):CVolumetricMovement(geometry),System(LINEAR_SOLVER_MODE::MESH_DEFORM){ + + /*--- Initialize the number of spatial dimensions, length of the state + vector (same as spatial dimensions for grid deformation), and grid nodes. ---*/ + + nVar = geometry->GetnDim(); + nPoint = geometry->GetnPoint(); + nPointDomain = geometry->GetnPointDomain(); + + nIterMesh = 0; + + /*--- Initialize matrix, solution, and r.h.s. structures for the linear solver. ---*/ + if (config->GetVolumetric_Movement() || config->GetSmoothGradient()) { + LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); + LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); + StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); + } +}; + + +void CLinearElasticity::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, + bool ForwardProjectionDerivative) { + unsigned long Tot_Iter = 0; + su2double MinVolume, MaxVolume; + + /*--- Retrieve number or iterations, tol, output, etc. from config ---*/ + + auto Screen_Output = config->GetDeform_Output(); + auto Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); + + /*--- Disable the screen output if we're running SU2_CFD ---*/ + + if (config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD && !Derivative) Screen_Output = false; + if (config->GetSmoothGradient()) Screen_Output = true; + + /*--- Set the number of nonlinear iterations to 1 if Derivative computation is enabled ---*/ + + if (Derivative) Nonlinear_Iter = 1; + + /*--- Loop over the total number of grid deformation iterations. The surface +deformation can be divided into increments to help with stability. In +particular, the linear elasticity equations hold only for small deformations. ---*/ + + for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { + /*--- Initialize vector and sparse matrix ---*/ + LinSysSol.SetValZero(); + LinSysRes.SetValZero(); + StiffMatrix.SetValZero(); + + /*--- Compute the stiffness matrix entries for all nodes/elements in the + mesh. FEA uses a finite element method discretization of the linear + elasticity equations (transfers element stiffnesses to point-to-point). ---*/ + + MinVolume = SetFEAMethodContributions_Elem(geometry, config); + + /*--- Set the boundary and volume displacements (as prescribed by the + design variable perturbations controlling the surface shape) + as a Dirichlet BC. ---*/ + + SetBoundaryDisplacements(geometry, config); + + /*--- Fix the location of any points in the domain, if requested. ---*/ + + SetDomainDisplacements(geometry, config); + + /*--- Set the boundary derivatives (overrides the actual displacements) ---*/ + + if (Derivative) { + SetBoundaryDerivatives(geometry, config, ForwardProjectionDerivative); + } + + /*--- Communicate any prescribed boundary displacements via MPI, + so that all nodes have the same solution and r.h.s. entries + across all partitions. ---*/ + + CSysMatrixComms::Initiate(LinSysSol, geometry, config); + CSysMatrixComms::Complete(LinSysSol, geometry, config); + + CSysMatrixComms::Initiate(LinSysRes, geometry, config); + CSysMatrixComms::Complete(LinSysRes, geometry, config); + + /*--- Definition of the preconditioner matrix vector multiplication, and linear solver ---*/ + + /*--- To keep legacy behavior ---*/ + System.SetToleranceType(LinearToleranceType::RELATIVE); + + /*--- If we want no derivatives or the direct derivatives, we solve the system using the + * normal matrix vector product and preconditioner. For the mesh sensitivities using + * the discrete adjoint method we solve the system using the transposed matrix. ---*/ + if (!Derivative || ((config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD) && Derivative) || + (config->GetSmoothGradient() && ForwardProjectionDerivative)) { + Tot_Iter = System.Solve(StiffMatrix, LinSysRes, LinSysSol, geometry, config); + } else if (Derivative && (config->GetKind_SU2() == SU2_COMPONENT::SU2_DOT)) { + Tot_Iter = System.Solve_b(StiffMatrix, LinSysRes, LinSysSol, geometry, config); + } + su2double Residual = System.GetResidual(); + + /*--- Update the grid coordinates and cell volumes using the solution + of the linear system (usol contains the x, y, z displacements). ---*/ + + if (!Derivative) { + UpdateGridCoord(geometry, config); + } else { + UpdateGridCoord_Derivatives(geometry, config, ForwardProjectionDerivative); + } + if (UpdateGeo) { + UpdateDualGrid(geometry, config); + } + + + if (!Derivative) { + /*--- Check for failed deformation (negative volumes). ---*/ + + ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); + + /*--- Calculate amount of nonconvex elements ---*/ + + ComputenNonconvexElements(geometry, Screen_Output); + } + + /*--- Set number of iterations in the mesh update. ---*/ + + Set_nIterMesh(Tot_Iter); + + if (rank == MASTER_NODE && Screen_Output) { + cout << "Non-linear iter.: " << iNonlinear_Iter + 1 << "/" << Nonlinear_Iter << ". Linear iter.: " << Tot_Iter + << ". "; + if (nDim == 2) + cout << "Min. area: " << MinVolume << ". Error: " << Residual << "." << endl; + else + cout << "Min. volume: " << MinVolume << ". Error: " << Residual << "." << endl; + } + } +} + +void CLinearElasticity::UpdateGridCoord(CGeometry* geometry, CConfig* config) { + cout << "updating the grid coordinates" << endl; + unsigned short iDim; + unsigned long iPoint, total_index; + su2double new_coord; + + /*--- Update the grid coordinates using the solution of the linear system +after grid deformation (LinSysSol contains the x, y, z displacements). ---*/ + + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + new_coord = geometry->nodes->GetCoord(iPoint, iDim) + LinSysSol[total_index]; + if (fabs(new_coord) < EPS * EPS) new_coord = 0.0; + geometry->nodes->SetCoord(iPoint, iDim, new_coord); + } + + /*--- LinSysSol contains the non-transformed displacements in the periodic halo cells. + * Hence we still need a communication of the transformed coordinates, otherwise periodicity + * is not maintained. ---*/ + + geometry->InitiateComms(geometry, config, COORDINATES); + geometry->CompleteComms(geometry, config, COORDINATES); +} + +void CLinearElasticity::UpdateGridCoord_Derivatives(CGeometry* geometry, CConfig* config, + bool ForwardProjectionDerivative) { + unsigned short iDim, iMarker; + unsigned long iPoint, total_index, iVertex; + auto* new_coord = new su2double[3]; + + SU2_COMPONENT Kind_SU2 = config->GetKind_SU2(); + + /*--- Update derivatives of the grid coordinates using the solution of the linear system + after grid deformation (LinSysSol contains the derivatives of the x, y, z displacements). ---*/ + if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + new_coord[0] = 0.0; + new_coord[1] = 0.0; + new_coord[2] = 0.0; + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + new_coord[iDim] = geometry->nodes->GetCoord(iPoint, iDim); + SU2_TYPE::SetDerivative(new_coord[iDim], SU2_TYPE::GetValue(LinSysSol[total_index])); + } + geometry->nodes->SetCoord(iPoint, new_coord); + } + } else if ((Kind_SU2 == SU2_COMPONENT::SU2_DOT) && !ForwardProjectionDerivative) { + // need to reset here, since we read out the whole vector, but are only interested in boundary derivatives. + if (config->GetSmoothGradient()) { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + geometry->SetSensitivity(iPoint, iDim, 0.0); + } + } + } + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetSolid_Wall(iMarker) || (config->GetMarker_All_DV(iMarker) == YES)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + if (geometry->nodes->GetDomain(iPoint)) { + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + geometry->SetSensitivity(iPoint, iDim, LinSysSol[total_index]); + } + } + } + } + } + } else if (config->GetSmoothGradient() && ForwardProjectionDerivative) { + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + geometry->SetSensitivity(iPoint, iDim, LinSysSol[total_index]); + } + } + } + + delete[] new_coord; +} + + +void CLinearElasticity::ComputeSolid_Wall_Distance(CGeometry* geometry, CConfig* config, su2double& MinDistance, + su2double& MaxDistance) const { + unsigned long nVertex_SolidWall, ii, jj, iVertex, iPoint, pointID; + unsigned short iMarker, iDim; + su2double dist, MaxDistance_Local, MinDistance_Local; + int rankID; + + /*--- Initialize min and max distance ---*/ + + MaxDistance = -1E22; + MinDistance = 1E22; + + /*--- Compute the total number of nodes on no-slip boundaries ---*/ + + nVertex_SolidWall = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); ++iMarker) { + if (config->GetSolid_Wall(iMarker)) nVertex_SolidWall += geometry->GetnVertex(iMarker); + } + + /*--- Allocate the vectors to hold boundary node coordinates + and its local ID. ---*/ + + vector Coord_bound(nDim * nVertex_SolidWall); + vector PointIDs(nVertex_SolidWall); + + /*--- Retrieve and store the coordinates of the no-slip boundary nodes + and their local point IDs. ---*/ + + ii = 0; + jj = 0; + for (iMarker = 0; iMarker < config->GetnMarker_All(); ++iMarker) { + if (config->GetSolid_Wall(iMarker)) { + for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); ++iVertex) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + PointIDs[jj++] = iPoint; + for (iDim = 0; iDim < nDim; ++iDim) Coord_bound[ii++] = geometry->nodes->GetCoord(iPoint, iDim); + } + } + } + + /*--- Build the ADT of the boundary nodes. ---*/ + + CADTPointsOnlyClass WallADT(nDim, nVertex_SolidWall, Coord_bound.data(), PointIDs.data(), true); + + /*--- Loop over all interior mesh nodes and compute the distances to each + of the no-slip boundary nodes. Store the minimum distance to the wall + for each interior mesh node. ---*/ + + if (WallADT.IsEmpty()) { + /*--- No solid wall boundary nodes in the entire mesh. + Set the wall distance to zero for all nodes. ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); ++iPoint) geometry->nodes->SetWall_Distance(iPoint, 0.0); + } else { + /*--- Solid wall boundary nodes are present. Compute the wall + distance for all nodes. ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); ++iPoint) { + WallADT.DetermineNearestNode(geometry->nodes->GetCoord(iPoint), dist, pointID, rankID); + geometry->nodes->SetWall_Distance(iPoint, dist); + + MaxDistance = max(MaxDistance, dist); + + /*--- To discard points on the surface we use > EPS ---*/ + + if (sqrt(dist) > EPS) MinDistance = min(MinDistance, dist); + } + + MaxDistance_Local = MaxDistance; + MaxDistance = 0.0; + MinDistance_Local = MinDistance; + MinDistance = 0.0; + +#ifdef HAVE_MPI + SU2_MPI::Allreduce(&MaxDistance_Local, &MaxDistance, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&MinDistance_Local, &MinDistance, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm()); +#else + MaxDistance = MaxDistance_Local; + MinDistance = MinDistance_Local; +#endif + } +} + +su2double CLinearElasticity::SetFEAMethodContributions_Elem(CGeometry* geometry, CConfig* config) { + unsigned short iVar, iDim, nNodes = 0, iNodes, StiffMatrix_nElem = 0; + unsigned long iElem, PointCorners[8]; + su2double **StiffMatrix_Elem = nullptr, CoordCorners[8][3]; + su2double MinVolume = 0.0, MaxVolume = 0.0, MinDistance = 0.0, MaxDistance = 0.0, ElemVolume = 0.0, + ElemDistance = 0.0; + + bool Screen_Output = config->GetDeform_Output(); + + /*--- Allocate maximum size (quadrilateral and hexahedron) ---*/ + + if (nDim == 2) + StiffMatrix_nElem = 8; + else + StiffMatrix_nElem = 24; + + StiffMatrix_Elem = new su2double*[StiffMatrix_nElem]; + for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) StiffMatrix_Elem[iVar] = new su2double[StiffMatrix_nElem]; + + /*--- Compute min volume in the entire mesh. ---*/ + + ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); + if (rank == MASTER_NODE && Screen_Output) + cout << "Min. volume: " << MinVolume << ", max. volume: " << MaxVolume << "." << endl; + + /*--- Compute the distance to the nearest surface if needed + as part of the stiffness calculation.. ---*/ + + if ((config->GetDeform_Stiffness_Type() == SOLID_WALL_DISTANCE) || (config->GetDeform_Limit() < 1E6)) { + ComputeSolid_Wall_Distance(geometry, config, MinDistance, MaxDistance); + if (rank == MASTER_NODE && Screen_Output) + cout << "Min. distance: " << MinDistance << ", max. distance: " << MaxDistance << "." << endl; + } + + /*--- Compute contributions from each element by forming the stiffness matrix (FEA) ---*/ + + for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { + if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; + if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; + if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; + if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; + if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; + + for (iNodes = 0; iNodes < nNodes; iNodes++) { + PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); + for (iDim = 0; iDim < nDim; iDim++) { + CoordCorners[iNodes][iDim] = geometry->nodes->GetCoord(PointCorners[iNodes], iDim); + } + } + + /*--- Extract Element volume and distance to compute the stiffness ---*/ + + ElemVolume = geometry->elem[iElem]->GetVolume(); + + if ((config->GetDeform_Stiffness_Type() == SOLID_WALL_DISTANCE)) { + ElemDistance = 0.0; + for (iNodes = 0; iNodes < nNodes; iNodes++) + ElemDistance += geometry->nodes->GetWall_Distance(PointCorners[iNodes]); + ElemDistance = ElemDistance / (su2double)nNodes; + } + + if (nDim == 2) + SetFEA_StiffMatrix2D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, ElemVolume, + ElemDistance); + if (nDim == 3) + SetFEA_StiffMatrix3D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, ElemVolume, + ElemDistance); + + AddFEA_StiffMatrix(geometry, StiffMatrix_Elem, PointCorners, nNodes); + } + + /*--- Deallocate memory and exit ---*/ + + for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) delete[] StiffMatrix_Elem[iVar]; + delete[] StiffMatrix_Elem; + + return MinVolume; +} + + +void CLinearElasticity::SetFEA_StiffMatrix2D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, + unsigned long PointCorners[8], su2double CoordCorners[8][3], + unsigned short nNodes, su2double ElemVolume, su2double ElemDistance) { + su2double B_Matrix[3][8], D_Matrix[3][3], Aux_Matrix[8][3]; + su2double Xi = 0.0, Eta = 0.0, Det = 0.0, E = 1 / EPS, Lambda = 0.0, Mu = 0.0, Nu = 0.0; + unsigned short iNode, iVar, jVar, kVar, iGauss, nGauss = 0; + su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; + su2double Location[4][3], Weight[4]; + unsigned short nVar = geometry->GetnDim(); + + for (iVar = 0; iVar < nNodes * nVar; iVar++) { + for (jVar = 0; jVar < nNodes * nVar; jVar++) { + StiffMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Integration formulae from "Shape functions and points of + integration of the Résumé" by Josselin DELMAS (2013) ---*/ + + /*--- Triangle. Nodes of numerical integration at 1 point (order 1). ---*/ + + if (nNodes == 3) { + nGauss = 1; + Location[0][0] = 0.333333333333333; + Location[0][1] = 0.333333333333333; + Weight[0] = 0.5; + } + + /*--- Quadrilateral. Nodes of numerical integration at 4 points (order 2). ---*/ + + if (nNodes == 4) { + nGauss = 4; + Location[0][0] = -0.577350269189626; + Location[0][1] = -0.577350269189626; + Weight[0] = 1.0; + Location[1][0] = 0.577350269189626; + Location[1][1] = -0.577350269189626; + Weight[1] = 1.0; + Location[2][0] = 0.577350269189626; + Location[2][1] = 0.577350269189626; + Weight[2] = 1.0; + Location[3][0] = -0.577350269189626; + Location[3][1] = 0.577350269189626; + Weight[3] = 1.0; + } + + for (iGauss = 0; iGauss < nGauss; iGauss++) { + Xi = Location[iGauss][0]; + Eta = Location[iGauss][1]; + + if (nNodes == 3) Det = ShapeFunc_Triangle(Xi, Eta, CoordCorners, DShapeFunction); + if (nNodes == 4) Det = ShapeFunc_Quadrilateral(Xi, Eta, CoordCorners, DShapeFunction); + + /*--- Compute the B Matrix ---*/ + + for (iVar = 0; iVar < 3; iVar++) + for (jVar = 0; jVar < nNodes * nVar; jVar++) B_Matrix[iVar][jVar] = 0.0; + + for (iNode = 0; iNode < nNodes; iNode++) { + B_Matrix[0][0 + iNode * nVar] = DShapeFunction[iNode][0]; + B_Matrix[1][1 + iNode * nVar] = DShapeFunction[iNode][1]; + + B_Matrix[2][0 + iNode * nVar] = DShapeFunction[iNode][1]; + B_Matrix[2][1 + iNode * nVar] = DShapeFunction[iNode][0]; + } + + /*--- Impose a type of stiffness for each element ---*/ + + switch (config->GetDeform_Stiffness_Type()) { + case INVERSE_VOLUME: + E = 1.0 / ElemVolume; + break; + case SOLID_WALL_DISTANCE: + E = 1.0 / ElemDistance; + break; + case CONSTANT_STIFFNESS: + E = 1.0 / EPS; + break; + } + + Nu = config->GetDeform_Coeff(); + Mu = E / (2.0 * (1.0 + Nu)); + Lambda = Nu * E / ((1.0 + Nu) * (1.0 - 2.0 * Nu)); + + /*--- Compute the D Matrix (for plane strain and 3-D)---*/ + + D_Matrix[0][0] = Lambda + 2.0 * Mu; + D_Matrix[0][1] = Lambda; + D_Matrix[0][2] = 0.0; + D_Matrix[1][0] = Lambda; + D_Matrix[1][1] = Lambda + 2.0 * Mu; + D_Matrix[1][2] = 0.0; + D_Matrix[2][0] = 0.0; + D_Matrix[2][1] = 0.0; + D_Matrix[2][2] = Mu; + + /*--- Compute the BT.D Matrix ---*/ + + for (iVar = 0; iVar < nNodes * nVar; iVar++) { + for (jVar = 0; jVar < 3; jVar++) { + Aux_Matrix[iVar][jVar] = 0.0; + for (kVar = 0; kVar < 3; kVar++) Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar] * D_Matrix[kVar][jVar]; + } + } + + /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original + matrix using Gauss integration ---*/ + + for (iVar = 0; iVar < nNodes * nVar; iVar++) { + for (jVar = 0; jVar < nNodes * nVar; jVar++) { + for (kVar = 0; kVar < 3; kVar++) { + StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar] * B_Matrix[kVar][jVar] * fabs(Det); + } + } + } + } +} + + +void CLinearElasticity::SetFEA_StiffMatrix3D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, + unsigned long PointCorners[8], su2double CoordCorners[8][3], + unsigned short nNodes, su2double ElemVolume, su2double ElemDistance) { + su2double B_Matrix[6][24], + D_Matrix[6][6] = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}, + Aux_Matrix[24][6]; + su2double Xi = 0.0, Eta = 0.0, Zeta = 0.0, Det = 0.0, Mu = 0.0, E = 0.0, Lambda = 0.0, Nu = 0.0; + unsigned short iNode, iVar, jVar, kVar, iGauss, nGauss = 0; + su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, + {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; + su2double Location[8][3], Weight[8]; + unsigned short nVar = geometry->GetnDim(); + + for (iVar = 0; iVar < nNodes * nVar; iVar++) { + for (jVar = 0; jVar < nNodes * nVar; jVar++) { + StiffMatrix_Elem[iVar][jVar] = 0.0; + } + } + + /*--- Integration formulae from "Shape functions and points of + integration of the Résumé" by Josselin Delmas (2013) ---*/ + + /*--- Tetrahedrons. Nodes of numerical integration at 1 point (order 1). ---*/ + + if (nNodes == 4) { + nGauss = 1; + Location[0][0] = 0.25; + Location[0][1] = 0.25; + Location[0][2] = 0.25; + Weight[0] = 0.166666666666666; + } + + /*--- Pyramids. Nodes numerical integration at 5 points. ---*/ + + if (nNodes == 5) { + nGauss = 5; + Location[0][0] = 0.5; + Location[0][1] = 0.0; + Location[0][2] = 0.1531754163448146; + Weight[0] = 0.133333333333333; + Location[1][0] = 0.0; + Location[1][1] = 0.5; + Location[1][2] = 0.1531754163448146; + Weight[1] = 0.133333333333333; + Location[2][0] = -0.5; + Location[2][1] = 0.0; + Location[2][2] = 0.1531754163448146; + Weight[2] = 0.133333333333333; + Location[3][0] = 0.0; + Location[3][1] = -0.5; + Location[3][2] = 0.1531754163448146; + Weight[3] = 0.133333333333333; + Location[4][0] = 0.0; + Location[4][1] = 0.0; + Location[4][2] = 0.6372983346207416; + Weight[4] = 0.133333333333333; + } + + /*--- Prism. Nodes of numerical integration at 6 points (order 3 in Xi, order 2 in Eta and Mu ). ---*/ + + if (nNodes == 6) { + nGauss = 6; + Location[0][0] = -0.577350269189626; + Location[0][1] = 0.166666666666667; + Location[0][2] = 0.166666666666667; + Weight[0] = 0.166666666666667; + Location[1][0] = -0.577350269189626; + Location[1][1] = 0.666666666666667; + Location[1][2] = 0.166666666666667; + Weight[1] = 0.166666666666667; + Location[2][0] = -0.577350269189626; + Location[2][1] = 0.166666666666667; + Location[2][2] = 0.666666666666667; + Weight[2] = 0.166666666666667; + Location[3][0] = 0.577350269189626; + Location[3][1] = 0.166666666666667; + Location[3][2] = 0.166666666666667; + Weight[3] = 0.166666666666667; + Location[4][0] = 0.577350269189626; + Location[4][1] = 0.666666666666667; + Location[4][2] = 0.166666666666667; + Weight[4] = 0.166666666666667; + Location[5][0] = 0.577350269189626; + Location[5][1] = 0.166666666666667; + Location[5][2] = 0.666666666666667; + Weight[5] = 0.166666666666667; + } + + /*--- Hexahedrons. Nodes of numerical integration at 6 points (order 3). ---*/ + + if (nNodes == 8) { + nGauss = 8; + Location[0][0] = -0.577350269189626; + Location[0][1] = -0.577350269189626; + Location[0][2] = -0.577350269189626; + Weight[0] = 1.0; + Location[1][0] = -0.577350269189626; + Location[1][1] = -0.577350269189626; + Location[1][2] = 0.577350269189626; + Weight[1] = 1.0; + Location[2][0] = -0.577350269189626; + Location[2][1] = 0.577350269189626; + Location[2][2] = -0.577350269189626; + Weight[2] = 1.0; + Location[3][0] = -0.577350269189626; + Location[3][1] = 0.577350269189626; + Location[3][2] = 0.577350269189626; + Weight[3] = 1.0; + Location[4][0] = 0.577350269189626; + Location[4][1] = -0.577350269189626; + Location[4][2] = -0.577350269189626; + Weight[4] = 1.0; + Location[5][0] = 0.577350269189626; + Location[5][1] = -0.577350269189626; + Location[5][2] = 0.577350269189626; + Weight[5] = 1.0; + Location[6][0] = 0.577350269189626; + Location[6][1] = 0.577350269189626; + Location[6][2] = -0.577350269189626; + Weight[6] = 1.0; + Location[7][0] = 0.577350269189626; + Location[7][1] = 0.577350269189626; + Location[7][2] = 0.577350269189626; + Weight[7] = 1.0; + } + + for (iGauss = 0; iGauss < nGauss; iGauss++) { + Xi = Location[iGauss][0]; + Eta = Location[iGauss][1]; + Zeta = Location[iGauss][2]; + + if (nNodes == 4) Det = ShapeFunc_Tetra(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + if (nNodes == 5) Det = ShapeFunc_Pyram(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + if (nNodes == 6) Det = ShapeFunc_Prism(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + if (nNodes == 8) Det = ShapeFunc_Hexa(Xi, Eta, Zeta, CoordCorners, DShapeFunction); + + /*--- Compute the B Matrix ---*/ + + for (iVar = 0; iVar < 6; iVar++) + for (jVar = 0; jVar < nNodes * nVar; jVar++) B_Matrix[iVar][jVar] = 0.0; + + for (iNode = 0; iNode < nNodes; iNode++) { + B_Matrix[0][0 + iNode * nVar] = DShapeFunction[iNode][0]; + B_Matrix[1][1 + iNode * nVar] = DShapeFunction[iNode][1]; + B_Matrix[2][2 + iNode * nVar] = DShapeFunction[iNode][2]; + + B_Matrix[3][0 + iNode * nVar] = DShapeFunction[iNode][1]; + B_Matrix[3][1 + iNode * nVar] = DShapeFunction[iNode][0]; + + B_Matrix[4][1 + iNode * nVar] = DShapeFunction[iNode][2]; + B_Matrix[4][2 + iNode * nVar] = DShapeFunction[iNode][1]; + + B_Matrix[5][0 + iNode * nVar] = DShapeFunction[iNode][2]; + B_Matrix[5][2 + iNode * nVar] = DShapeFunction[iNode][0]; + } + + /*--- Impose a type of stiffness for each element ---*/ + + switch (config->GetDeform_Stiffness_Type()) { + case INVERSE_VOLUME: + E = 1.0 / ElemVolume; + break; + case SOLID_WALL_DISTANCE: + E = 1.0 / ElemDistance; + break; + case CONSTANT_STIFFNESS: + E = 1.0 / EPS; + break; + } + + Nu = config->GetDeform_Coeff(); + Mu = E / (2.0 * (1.0 + Nu)); + Lambda = Nu * E / ((1.0 + Nu) * (1.0 - 2.0 * Nu)); + + /*--- Compute the D Matrix (for plane strain and 3-D)---*/ + + D_Matrix[0][0] = Lambda + 2.0 * Mu; + D_Matrix[0][1] = Lambda; + D_Matrix[0][2] = Lambda; + D_Matrix[1][0] = Lambda; + D_Matrix[1][1] = Lambda + 2.0 * Mu; + D_Matrix[1][2] = Lambda; + D_Matrix[2][0] = Lambda; + D_Matrix[2][1] = Lambda; + D_Matrix[2][2] = Lambda + 2.0 * Mu; + D_Matrix[3][3] = Mu; + D_Matrix[4][4] = Mu; + D_Matrix[5][5] = Mu; + + /*--- Compute the BT.D Matrix ---*/ + + for (iVar = 0; iVar < nNodes * nVar; iVar++) { + for (jVar = 0; jVar < 6; jVar++) { + Aux_Matrix[iVar][jVar] = 0.0; + for (kVar = 0; kVar < 6; kVar++) Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar] * D_Matrix[kVar][jVar]; + } + } + + /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original + matrix using Gauss integration ---*/ + + for (iVar = 0; iVar < nNodes * nVar; iVar++) { + for (jVar = 0; jVar < nNodes * nVar; jVar++) { + for (kVar = 0; kVar < 6; kVar++) { + StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar] * B_Matrix[kVar][jVar] * fabs(Det); + } + } + } + } +} + + +void CLinearElasticity::AddFEA_StiffMatrix(CGeometry* geometry, su2double** StiffMatrix_Elem, + unsigned long PointCorners[8], unsigned short nNodes) { + unsigned short iVar, jVar, iDim, jDim; + + unsigned short nVar = geometry->GetnDim(); + + su2double** StiffMatrix_Node; + StiffMatrix_Node = new su2double*[nVar]; + for (iVar = 0; iVar < nVar; iVar++) StiffMatrix_Node[iVar] = new su2double[nVar]; + + for (iVar = 0; iVar < nVar; iVar++) + for (jVar = 0; jVar < nVar; jVar++) StiffMatrix_Node[iVar][jVar] = 0.0; + + /*--- Transform the stiffness matrix for the hexahedral element into the + contributions for the individual nodes relative to each other. ---*/ + + for (iVar = 0; iVar < nNodes; iVar++) { + for (jVar = 0; jVar < nNodes; jVar++) { + for (iDim = 0; iDim < nVar; iDim++) { + for (jDim = 0; jDim < nVar; jDim++) { + StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar * nVar) + iDim][(jVar * nVar) + jDim]; + } + } + + StiffMatrix.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); + } + } + + /*--- Deallocate memory and exit ---*/ + + for (iVar = 0; iVar < nVar; iVar++) delete[] StiffMatrix_Node[iVar]; + delete[] StiffMatrix_Node; +} + +su2double CLinearElasticity::ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]) { + int i, j, k; + su2double c0, c1, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = Xi; + DShapeFunction[1][3] = Eta; + DShapeFunction[2][3] = 1 - Xi - Eta; + + /*--- dN/d xi, dN/d eta ---*/ + + DShapeFunction[0][0] = 1.0; + DShapeFunction[0][1] = 0.0; + DShapeFunction[1][0] = 0.0; + DShapeFunction[1][1] = 1.0; + DShapeFunction[2][0] = -1.0; + DShapeFunction[2][1] = -1.0; + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 3; k++) { + xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]; + ad[0][1] = -xs[0][1]; + ad[1][0] = -xs[1][0]; + ad[1][1] = xs[0][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = ad[0][0] * ad[1][1] - ad[0][1] * ad[1][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = ad[i][j] / xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 3; k++) { + c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1]; // dN/dx + c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1]; // dN/dy + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + } + + return xsj; +} + +su2double CLinearElasticity::ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]) { + int i, j, k; + su2double c0, c1, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.25 * (1.0 - Xi) * (1.0 - Eta); + DShapeFunction[1][3] = 0.25 * (1.0 + Xi) * (1.0 - Eta); + DShapeFunction[2][3] = 0.25 * (1.0 + Xi) * (1.0 + Eta); + DShapeFunction[3][3] = 0.25 * (1.0 - Xi) * (1.0 + Eta); + + /*--- dN/d xi, dN/d eta ---*/ + + DShapeFunction[0][0] = -0.25 * (1.0 - Eta); + DShapeFunction[0][1] = -0.25 * (1.0 - Xi); + DShapeFunction[1][0] = 0.25 * (1.0 - Eta); + DShapeFunction[1][1] = -0.25 * (1.0 + Xi); + DShapeFunction[2][0] = 0.25 * (1.0 + Eta); + DShapeFunction[2][1] = 0.25 * (1.0 + Xi); + DShapeFunction[3][0] = -0.25 * (1.0 + Eta); + DShapeFunction[3][1] = 0.25 * (1.0 - Xi); + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 4; k++) { + xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1]; + ad[0][1] = -xs[0][1]; + ad[1][0] = -xs[1][0]; + ad[1][1] = xs[0][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = ad[0][0] * ad[1][1] - ad[0][1] * ad[1][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 2; i++) { + for (j = 0; j < 2; j++) { + xs[i][j] = ad[i][j] / xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 4; k++) { + c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1]; // dN/dx + c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1]; // dN/dy + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + } + + return xsj; +} + +su2double CLinearElasticity::ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, + su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = Xi; + DShapeFunction[1][3] = Zeta; + DShapeFunction[2][3] = 1.0 - Xi - Eta - Zeta; + DShapeFunction[3][3] = Eta; + + /*--- dN/d xi, dN/d eta, dN/d zeta ---*/ + + DShapeFunction[0][0] = 1.0; + DShapeFunction[0][1] = 0.0; + DShapeFunction[0][2] = 0.0; + DShapeFunction[1][0] = 0.0; + DShapeFunction[1][1] = 0.0; + DShapeFunction[1][2] = 1.0; + DShapeFunction[2][0] = -1.0; + DShapeFunction[2][1] = -1.0; + DShapeFunction[2][2] = -1.0; + DShapeFunction[3][0] = 0.0; + DShapeFunction[3][1] = 1.0; + DShapeFunction[3][2] = 0.0; + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 4; k++) { + xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; + ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; + ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; + ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; + ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; + ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; + ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; + ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; + ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j] / xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 4; k++) { + c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; +} + +su2double CLinearElasticity::ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, + su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.25 * (-Xi + Eta + Zeta - 1.0) * (-Xi - Eta + Zeta - 1.0) / (1.0 - Zeta); + DShapeFunction[1][3] = 0.25 * (-Xi - Eta + Zeta - 1.0) * (Xi - Eta + Zeta - 1.0) / (1.0 - Zeta); + DShapeFunction[2][3] = 0.25 * (Xi + Eta + Zeta - 1.0) * (Xi - Eta + Zeta - 1.0) / (1.0 - Zeta); + DShapeFunction[3][3] = 0.25 * (Xi + Eta + Zeta - 1.0) * (-Xi + Eta + Zeta - 1.0) / (1.0 - Zeta); + DShapeFunction[4][3] = Zeta; + + /*--- dN/d xi ---*/ + + DShapeFunction[0][0] = 0.5 * (Zeta - Xi - 1.0) / (Zeta - 1.0); + DShapeFunction[1][0] = 0.5 * Xi / (Zeta - 1.0); + DShapeFunction[2][0] = 0.5 * (1.0 - Zeta - Xi) / (Zeta - 1.0); + DShapeFunction[3][0] = DShapeFunction[1][0]; + DShapeFunction[4][0] = 0.0; + + /*--- dN/d eta ---*/ + + DShapeFunction[0][1] = 0.5 * Eta / (Zeta - 1.0); + DShapeFunction[1][1] = 0.5 * (Zeta - Eta - 1.0) / (Zeta - 1.0); + DShapeFunction[2][1] = DShapeFunction[0][1]; + DShapeFunction[3][1] = 0.5 * (1.0 - Zeta - Eta) / (Zeta - 1.0); + DShapeFunction[4][1] = 0.0; + + /*--- dN/d zeta ---*/ + + DShapeFunction[0][2] = 0.25 * (-1.0 + 2.0 * Zeta - Zeta * Zeta - Eta * Eta + Xi * Xi) / ((1.0 - Zeta) * (1.0 - Zeta)); + DShapeFunction[1][2] = 0.25 * (-1.0 + 2.0 * Zeta - Zeta * Zeta + Eta * Eta - Xi * Xi) / ((1.0 - Zeta) * (1.0 - Zeta)); + DShapeFunction[2][2] = DShapeFunction[0][2]; + DShapeFunction[3][2] = DShapeFunction[1][2]; + DShapeFunction[4][2] = 1.0; + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 5; k++) { + xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; + ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; + ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; + ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; + ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; + ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; + ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; + ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; + ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j] / xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 5; k++) { + c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; +} + +su2double CLinearElasticity::ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, + su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.5 * Eta * (1.0 - Xi); + DShapeFunction[1][3] = 0.5 * Zeta * (1.0 - Xi); + DShapeFunction[2][3] = 0.5 * (1.0 - Eta - Zeta) * (1.0 - Xi); + DShapeFunction[3][3] = 0.5 * Eta * (Xi + 1.0); + DShapeFunction[4][3] = 0.5 * Zeta * (Xi + 1.0); + DShapeFunction[5][3] = 0.5 * (1.0 - Eta - Zeta) * (Xi + 1.0); + + /*--- dN/d Xi, dN/d Eta, dN/d Zeta ---*/ + + DShapeFunction[0][0] = -0.5 * Eta; + DShapeFunction[0][1] = 0.5 * (1.0 - Xi); + DShapeFunction[0][2] = 0.0; + DShapeFunction[1][0] = -0.5 * Zeta; + DShapeFunction[1][1] = 0.0; + DShapeFunction[1][2] = 0.5 * (1.0 - Xi); + DShapeFunction[2][0] = -0.5 * (1.0 - Eta - Zeta); + DShapeFunction[2][1] = -0.5 * (1.0 - Xi); + DShapeFunction[2][2] = -0.5 * (1.0 - Xi); + DShapeFunction[3][0] = 0.5 * Eta; + DShapeFunction[3][1] = 0.5 * (Xi + 1.0); + DShapeFunction[3][2] = 0.0; + DShapeFunction[4][0] = 0.5 * Zeta; + DShapeFunction[4][1] = 0.0; + DShapeFunction[4][2] = 0.5 * (Xi + 1.0); + DShapeFunction[5][0] = 0.5 * (1.0 - Eta - Zeta); + DShapeFunction[5][1] = -0.5 * (Xi + 1.0); + DShapeFunction[5][2] = -0.5 * (Xi + 1.0); + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 6; k++) { + xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; + ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; + ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; + ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; + ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; + ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; + ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; + ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; + ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; + + /*--- Jacobian inverse ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j] / xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 6; k++) { + c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; +} + +su2double CLinearElasticity::ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], + su2double DShapeFunction[8][4]) { + int i, j, k; + su2double c0, c1, c2, xsj; + su2double xs[3][3], ad[3][3]; + + /*--- Shape functions ---*/ + + DShapeFunction[0][3] = 0.125 * (1.0 - Xi) * (1.0 - Eta) * (1.0 - Zeta); + DShapeFunction[1][3] = 0.125 * (1.0 + Xi) * (1.0 - Eta) * (1.0 - Zeta); + DShapeFunction[2][3] = 0.125 * (1.0 + Xi) * (1.0 + Eta) * (1.0 - Zeta); + DShapeFunction[3][3] = 0.125 * (1.0 - Xi) * (1.0 + Eta) * (1.0 - Zeta); + DShapeFunction[4][3] = 0.125 * (1.0 - Xi) * (1.0 - Eta) * (1.0 + Zeta); + DShapeFunction[5][3] = 0.125 * (1.0 + Xi) * (1.0 - Eta) * (1.0 + Zeta); + DShapeFunction[6][3] = 0.125 * (1.0 + Xi) * (1.0 + Eta) * (1.0 + Zeta); + DShapeFunction[7][3] = 0.125 * (1.0 - Xi) * (1.0 + Eta) * (1.0 + Zeta); + + /*--- dN/d xi ---*/ + + DShapeFunction[0][0] = -0.125 * (1.0 - Eta) * (1.0 - Zeta); + DShapeFunction[1][0] = 0.125 * (1.0 - Eta) * (1.0 - Zeta); + DShapeFunction[2][0] = 0.125 * (1.0 + Eta) * (1.0 - Zeta); + DShapeFunction[3][0] = -0.125 * (1.0 + Eta) * (1.0 - Zeta); + DShapeFunction[4][0] = -0.125 * (1.0 - Eta) * (1.0 + Zeta); + DShapeFunction[5][0] = 0.125 * (1.0 - Eta) * (1.0 + Zeta); + DShapeFunction[6][0] = 0.125 * (1.0 + Eta) * (1.0 + Zeta); + DShapeFunction[7][0] = -0.125 * (1.0 + Eta) * (1.0 + Zeta); + + /*--- dN/d eta ---*/ + + DShapeFunction[0][1] = -0.125 * (1.0 - Xi) * (1.0 - Zeta); + DShapeFunction[1][1] = -0.125 * (1.0 + Xi) * (1.0 - Zeta); + DShapeFunction[2][1] = 0.125 * (1.0 + Xi) * (1.0 - Zeta); + DShapeFunction[3][1] = 0.125 * (1.0 - Xi) * (1.0 - Zeta); + DShapeFunction[4][1] = -0.125 * (1.0 - Xi) * (1.0 + Zeta); + DShapeFunction[5][1] = -0.125 * (1.0 + Xi) * (1.0 + Zeta); + DShapeFunction[6][1] = 0.125 * (1.0 + Xi) * (1.0 + Zeta); + DShapeFunction[7][1] = 0.125 * (1.0 - Xi) * (1.0 + Zeta); + + /*--- dN/d zeta ---*/ + + DShapeFunction[0][2] = -0.125 * (1.0 - Xi) * (1.0 - Eta); + DShapeFunction[1][2] = -0.125 * (1.0 + Xi) * (1.0 - Eta); + DShapeFunction[2][2] = -0.125 * (1.0 + Xi) * (1.0 + Eta); + DShapeFunction[3][2] = -0.125 * (1.0 - Xi) * (1.0 + Eta); + DShapeFunction[4][2] = 0.125 * (1.0 - Xi) * (1.0 - Eta); + DShapeFunction[5][2] = 0.125 * (1.0 + Xi) * (1.0 - Eta); + DShapeFunction[6][2] = 0.125 * (1.0 + Xi) * (1.0 + Eta); + DShapeFunction[7][2] = 0.125 * (1.0 - Xi) * (1.0 + Eta); + + /*--- Jacobian transformation ---*/ + + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = 0.0; + for (k = 0; k < 8; k++) { + xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; + } + } + } + + /*--- Adjoint to Jacobian ---*/ + + ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; + ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; + ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; + ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; + ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; + ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; + ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; + ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; + ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; + + /*--- Determinant of Jacobian ---*/ + + xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; + + /*--- Jacobian inverse ---*/ + for (i = 0; i < 3; i++) { + for (j = 0; j < 3; j++) { + xs[i][j] = ad[i][j] / xsj; + } + } + + /*--- Derivatives with repect to global coordinates ---*/ + + for (k = 0; k < 8; k++) { + c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx + c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy + c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz + DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi + DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta + DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta + } + + return xsj; +} + +void CLinearElasticity::SetDomainDisplacements(CGeometry* geometry, CConfig* config) { + unsigned short iDim, nDim = geometry->GetnDim(); + unsigned long iPoint, total_index; + + if (config->GetHold_GridFixed()) { + auto MinCoordValues = config->GetHold_GridFixed_Coord(); + auto MaxCoordValues = &config->GetHold_GridFixed_Coord()[3]; + + /*--- Set to zero displacements of all the points that are not going to be moved + except the surfaces ---*/ + + for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { + auto Coord = geometry->nodes->GetCoord(iPoint); + for (iDim = 0; iDim < nDim; iDim++) { + if ((Coord[iDim] < MinCoordValues[iDim]) || (Coord[iDim] > MaxCoordValues[iDim])) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Don't move the volume grid outside the limits based + on the distance to the solid surface ---*/ + + if (config->GetDeform_Limit() < 1E6) { + for (iPoint = 0; iPoint < nPoint; iPoint++) { + if (geometry->nodes->GetWall_Distance(iPoint) >= config->GetDeform_Limit()) { + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } +} + + +void CLinearElasticity::SetBoundaryDisplacements(CGeometry* geometry, CConfig* config) { + unsigned short iDim, nDim = geometry->GetnDim(), iMarker, axis = 0; + unsigned long iPoint, total_index, iVertex; + su2double *VarCoord, MeanCoord[3] = {0.0, 0.0, 0.0}, VarIncrement = 1.0; + + /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically + deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming + meshes after imposing design variable surface deformations (DV_MARKER). ---*/ + + SU2_COMPONENT Kind_SU2 = config->GetKind_SU2(); + + /*--- If requested (no by default) impose the surface deflections in + increments and solve the grid deformation equations iteratively with + successive small deformations. ---*/ + + VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); + + /*--- As initialization, set to zero displacements of all the surfaces except the symmetry + plane (which is treated specially, see below), internal and the send-receive boundaries ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_KindBC(iMarker) != SYMMETRY_PLANE) && + (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && + (config->GetMarker_All_KindBC(iMarker) != INTERNAL_BOUNDARY))) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Set the known displacements, note that some points of the moving surfaces + could be on on the symmetry plane, we should specify DeleteValsRowi again (just in case) ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_DEF)) || + ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD) && + (config->GetMarker_All_DV(iMarker) == YES)) || + ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_DOT))) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Set to zero displacements of the normal component for the symmetry plane condition ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE)) { + su2double* Coord_0 = nullptr; + + for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = 0.0; + + /*--- Store the coord of the first point to help identify the axis. ---*/ + + iPoint = geometry->vertex[iMarker][0]->GetNode(); + Coord_0 = geometry->nodes->GetCoord(iPoint); + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->nodes->GetCoord(iPoint); + for (iDim = 0; iDim < nDim; iDim++) + MeanCoord[iDim] += (VarCoord[iDim] - Coord_0[iDim]) * (VarCoord[iDim] - Coord_0[iDim]); + } + for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = sqrt(MeanCoord[iDim]); + if (nDim == 3) { + if ((MeanCoord[0] <= MeanCoord[1]) && (MeanCoord[0] <= MeanCoord[2])) axis = 0; + if ((MeanCoord[1] <= MeanCoord[0]) && (MeanCoord[1] <= MeanCoord[2])) axis = 1; + if ((MeanCoord[2] <= MeanCoord[0]) && (MeanCoord[2] <= MeanCoord[1])) axis = 2; + } else { + if ((MeanCoord[0] <= MeanCoord[1])) axis = 0; + if ((MeanCoord[1] <= MeanCoord[0])) axis = 1; + } + + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + total_index = iPoint * nDim + axis; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + + /*--- Don't move the nearfield plane ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = 0.0; + LinSysSol[total_index] = 0.0; + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } + + /*--- Move the FSI interfaces ---*/ + + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_ZoneInterface(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); + StiffMatrix.DeleteValsRowi(total_index); + } + } + } + } +} + +void CLinearElasticity::SetBoundaryDerivatives(CGeometry* geometry, CConfig* config, + bool ForwardProjectionDerivative) { + unsigned short iDim, iMarker; + unsigned long iPoint, total_index, iVertex; + + su2double* VarCoord; + SU2_COMPONENT Kind_SU2 = config->GetKind_SU2(); + if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_DV(iMarker) == YES)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); + LinSysSol[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); + } + } + } + } + if (LinSysRes.norm() == 0.0) cout << "Warning: Derivatives are zero!" << endl; + } else if ((Kind_SU2 == SU2_COMPONENT::SU2_DOT) && !ForwardProjectionDerivative) { + for (iPoint = 0; iPoint < nPoint; iPoint++) { + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); + LinSysSol[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); + } + } + } else if (config->GetSmoothGradient() && ForwardProjectionDerivative) { + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + if ((config->GetMarker_All_DV(iMarker) == YES)) { + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + for (iDim = 0; iDim < nDim; iDim++) { + total_index = iPoint * nDim + iDim; + LinSysRes[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); + LinSysSol[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); + } + } + } + } + if (LinSysRes.norm() == 0.0) cout << "Warning: Derivatives are zero!" << endl; + } +} diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp new file mode 100644 index 00000000000..b569c7c9d28 --- /dev/null +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -0,0 +1,234 @@ +/*! + * \file CRadialBasisFunctionInterpolation.cpp + * \brief Subroutines for moving mesh volume elements using Radial Basis Function interpolation. + * \author F. van Steen + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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/grid_movement/CRadialBasisFunctionInterpolation.hpp" +#include "../../include/interface_interpolation/CRadialBasisFunction.hpp" +#include "../../include/toolboxes/geometry_toolbox.hpp" + + +CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config) : CVolumetricMovement(geometry) { + /*--- Retrieve type of RBF and if applicable its support radius ---*/ + kindRBF = config->GetKindRadialBasisFunction(); + radius = config->GetRadialBasisFunctionParameter(); + + controlNodes = &boundaryNodes; +} + +void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, + bool ForwardProjectionDerivative){ + /*--- Retrieving number of deformation steps. ---*/ + auto Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); + + /*--- Assigning the node types ---*/ + SetControlNodes(geometry, config); + SetInternalNodes(geometry); + + /*--- Looping over the number of deformation iterations ---*/ + for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { + + /*--- Obtaining the interpolation coefficients of the control nodes ---*/ + GetInterpolationCoefficients(geometry, config, iNonlinear_Iter); + + /*--- Updating the coordinates of the grid ---*/ + UpdateGridCoord(geometry, config); + } +} + +void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* geometry, CConfig* config, unsigned long iNonlinear_Iter){ + + /*--- Deformation vector only has to be set once ---*/ + if(iNonlinear_Iter == 0){ + SetDeformationVector(geometry, config); + } + + /*--- Computing the interpolation matrix with RBF evaluations based on Euclidean distance ---*/ + SetInterpolationMatrix(geometry, config); + + /*--- Solving the RBF system to get the interpolation coefficients ---*/ + SolveRBF_System(); +} + + +void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CConfig* config){ + unsigned short iMarker; + unsigned short iVertex; + + + /*--- Total number of boundary nodes (including duplicates of shared boundaries) ---*/ + unsigned long nBoundNodes = 0; + for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ + nBoundNodes += geometry->nVertex[iMarker]; + } + + /*--- Vector with boudary nodes has at most nBoundNodes ---*/ + boundaryNodes.resize(nBoundNodes); + + /*--- Storing of the global, marker and vertex indices ---*/ + unsigned long count = 0; + for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ + for(iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ + boundaryNodes[count+iVertex] = new CRadialBasisFunctionNode(geometry, iMarker, iVertex); + } + count += geometry->nVertex[iMarker]; + } + + /*--- Sorting of the boundary nodes based on global index ---*/ + sort(boundaryNodes.begin(), boundaryNodes.end(), Compare); + + /*--- Obtaining unique set of boundary nodes ---*/ + boundaryNodes.resize(std::distance(boundaryNodes.begin(), unique(boundaryNodes.begin(), boundaryNodes.end(), Equal))); + + /*--- Updating the number of boundary nodes ---*/ + nBoundaryNodes = boundaryNodes.size(); + +} + +void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geometry, CConfig* config){ + unsigned long iNode, jNode; + + /*--- Initialization of the interpolation matrix ---*/ + interpMat.Initialize(controlNodes->size()); + + /*--- Construction of the interpolation matrix. + Since this matrix is symmetric only upper halve has to be considered ---*/ + + /*--- Looping over the target nodes ---*/ + for(iNode = 0; iNode < controlNodes->size(); iNode++ ){ + /*--- Looping over the control nodes ---*/ + for (jNode = iNode; jNode < controlNodes->size(); jNode++){ + + /*--- Distance between nodes ---*/ + auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); + + /*--- Evaluation of RBF ---*/ + interpMat(iNode, jNode) = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + } + } + + /*--- Obtaining lower halve using symmetry ---*/ + const bool kernelIsSPD = (kindRBF == RADIAL_BASIS::WENDLAND_C2) || (kindRBF == RADIAL_BASIS::GAUSSIAN) || + (kindRBF == RADIAL_BASIS::INV_MULTI_QUADRIC); + interpMat.Invert(kernelIsSPD); + +} + +void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry, CConfig* config){ + /* --- Initialization of the deformation vector ---*/ + deformationVector.resize(controlNodes->size()*nDim, 0.0); + + /*--- If requested (no by default) impose the surface deflections in + increments and solve the grid deformation with + successive small deformations. ---*/ + su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); + + /*--- Setting nonzero displacements of the moving markers ---*/ + for(auto i = 0; i < controlNodes->size(); i++){ + if(config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())){ + for(auto iDim = 0; iDim < nDim; iDim++){ + deformationVector[i+iDim*controlNodes->size()] = SU2_TYPE::GetValue(geometry->vertex[(*controlNodes)[i]->GetMarker()][(*controlNodes)[i]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); + } + } + } +} + +void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry){ + + /*--- resizing the internal nodes vector ---*/ + nInternalNodes = geometry->GetnPoint() - nBoundaryNodes; + internalNodes.resize(nInternalNodes); + + /*--- Looping over all nodes and check if present in boundary nodes vector ---*/ + unsigned long idx_cnt = 0, idx_control = 0; + for(unsigned long iNode = 0; iNode < geometry->GetnPoint(); iNode++){ + + /*--- If iNode is equal to boundaryNodes[idx_control] + then this node is a boundary node and idx_control can be updated ---*/ + if(idx_control < nBoundaryNodes && iNode == boundaryNodes[idx_control]->GetIndex()){idx_control++;} + + /*--- If not equal then the node is an internal node ---*/ + else{ + internalNodes[idx_cnt] = iNode; + idx_cnt++; + } + } +} + + +void CRadialBasisFunctionInterpolation::SolveRBF_System(){ + + /*--- resizing the interpolation coefficient vector ---*/ + coefficients.resize(nDim*controlNodes->size()); + + /*--- Looping through the dimensions in order to find the interpolation coefficients for each direction ---*/ + unsigned short iDim; + for(iDim = 0; iDim < nDim; iDim++){ + interpMat.MatVecMult(deformationVector.begin()+iDim*controlNodes->size(), coefficients.begin()+iDim*controlNodes->size()); + } +} + +void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CConfig* config){ + unsigned long iNode, cNode; + unsigned short iDim; + + /*--- Vector for storing the coordinate variation ---*/ + su2double var_coord[nDim]; + + /*--- Loop over the internal nodes ---*/ + for(iNode = 0; iNode < nInternalNodes; iNode++){ + + /*--- Loop for contribution of each control node ---*/ + for(cNode = 0; cNode < controlNodes->size(); cNode++){ + + /*--- Determine distance between considered internal and control node ---*/ + auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(internalNodes[iNode])); + + /*--- Evaluate RBF based on distance ---*/ + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + + /*--- Add contribution to total coordinate variation ---*/ + for( iDim = 0; iDim < nDim; iDim++){ + var_coord[iDim] += rbf*coefficients[cNode + iDim*controlNodes->size()]; + } + } + + /*--- Apply the coordinate variation and resetting the var_coord vector to zero ---*/ + for(iDim = 0; iDim < nDim; iDim++){ + geometry->nodes->AddCoord(internalNodes[iNode], iDim, var_coord[iDim]); + var_coord[iDim] = 0; + } + } + + /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ + for(cNode = 0; cNode < controlNodes->size(); cNode++){ + if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ + for(iDim = 0; iDim < nDim; iDim++){ + geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*controlNodes->size()]); + } + } + } + +} diff --git a/Common/src/grid_movement/CRadialBasisFunctionNode.cpp b/Common/src/grid_movement/CRadialBasisFunctionNode.cpp new file mode 100644 index 00000000000..ac3addf5303 --- /dev/null +++ b/Common/src/grid_movement/CRadialBasisFunctionNode.cpp @@ -0,0 +1,34 @@ +/*! + * \file CRadialBasisFunctionNode.cpp + * \brief Class for defining the nodes in the RBF interpolation. + * \author F. van Steen + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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/grid_movement/CRadialBasisFunctionNode.hpp" + +CRadialBasisFunctionNode::CRadialBasisFunctionNode(CGeometry* geometry, unsigned short marker_val, unsigned long vertex_val){ + idx = geometry->vertex[marker_val][vertex_val]->GetNode(); + marker_idx = marker_val; + vertex_idx = vertex_val; +}; \ No newline at end of file diff --git a/Common/src/grid_movement/CVolumetricMovement.cpp b/Common/src/grid_movement/CVolumetricMovement.cpp index 5b09a9cdd71..73ed22099a4 100644 --- a/Common/src/grid_movement/CVolumetricMovement.cpp +++ b/Common/src/grid_movement/CVolumetricMovement.cpp @@ -26,63 +26,22 @@ */ #include "../../include/grid_movement/CVolumetricMovement.hpp" -#include "../../include/adt/CADTPointsOnlyClass.hpp" -#include "../../include/toolboxes/geometry_toolbox.hpp" -CVolumetricMovement::CVolumetricMovement() : CGridMovement(), System(LINEAR_SOLVER_MODE::MESH_DEFORM) {} -CVolumetricMovement::CVolumetricMovement(CGeometry* geometry, CConfig* config) - : CGridMovement(), System(LINEAR_SOLVER_MODE::MESH_DEFORM) { +CVolumetricMovement::CVolumetricMovement() : CGridMovement() {} + +CVolumetricMovement::CVolumetricMovement(CGeometry* geometry) : CGridMovement() { size = SU2_MPI::GetSize(); rank = SU2_MPI::GetRank(); - /*--- Initialize the number of spatial dimensions, length of the state - vector (same as spatial dimensions for grid deformation), and grid nodes. ---*/ - nDim = geometry->GetnDim(); - nVar = geometry->GetnDim(); - nPoint = geometry->GetnPoint(); - nPointDomain = geometry->GetnPointDomain(); - - nIterMesh = 0; - - /*--- Initialize matrix, solution, and r.h.s. structures for the linear solver. ---*/ - if (config->GetVolumetric_Movement() || config->GetSmoothGradient()) { - LinSysSol.Initialize(nPoint, nPointDomain, nVar, 0.0); - LinSysRes.Initialize(nPoint, nPointDomain, nVar, 0.0); - StiffMatrix.Initialize(nPoint, nPointDomain, nVar, nVar, false, geometry, config); - } } CVolumetricMovement::~CVolumetricMovement() = default; -void CVolumetricMovement::UpdateGridCoord(CGeometry* geometry, CConfig* config) { - unsigned short iDim; - unsigned long iPoint, total_index; - su2double new_coord; - - /*--- Update the grid coordinates using the solution of the linear system - after grid deformation (LinSysSol contains the x, y, z displacements). ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++) - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - new_coord = geometry->nodes->GetCoord(iPoint, iDim) + LinSysSol[total_index]; - if (fabs(new_coord) < EPS * EPS) new_coord = 0.0; - geometry->nodes->SetCoord(iPoint, iDim, new_coord); - } - - /*--- LinSysSol contains the non-transformed displacements in the periodic halo cells. - * Hence we still need a communication of the transformed coordinates, otherwise periodicity - * is not maintained. ---*/ - - geometry->InitiateComms(geometry, config, COORDINATES); - geometry->CompleteComms(geometry, config, COORDINATES); -} - void CVolumetricMovement::UpdateDualGrid(CGeometry* geometry, CConfig* config) { /*--- After moving all nodes, update the dual mesh. Recompute the edges and - dual mesh control volumes in the domain and on the boundaries. ---*/ +dual mesh control volumes in the domain and on the boundaries. ---*/ geometry->SetControlVolume(config, UPDATE); geometry->SetBoundControlVolume(config, UPDATE); @@ -93,7 +52,7 @@ void CVolumetricMovement::UpdateMultiGrid(CGeometry** geometry, CConfig* config) unsigned short iMGfine, iMGlevel, nMGlevel = config->GetnMGLevels(); /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels. ---*/ +including computing the grid velocities on the coarser levels. ---*/ for (iMGlevel = 1; iMGlevel <= nMGlevel; iMGlevel++) { iMGfine = iMGlevel - 1; @@ -104,121 +63,6 @@ void CVolumetricMovement::UpdateMultiGrid(CGeometry** geometry, CConfig* config) } } -void CVolumetricMovement::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, - bool ForwardProjectionDerivative) { - unsigned long Tot_Iter = 0; - su2double MinVolume, MaxVolume; - - /*--- Retrieve number or iterations, tol, output, etc. from config ---*/ - - auto Screen_Output = config->GetDeform_Output(); - auto Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); - - /*--- Disable the screen output if we're running SU2_CFD ---*/ - - if (config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD && !Derivative) Screen_Output = false; - if (config->GetSmoothGradient()) Screen_Output = true; - - /*--- Set the number of nonlinear iterations to 1 if Derivative computation is enabled ---*/ - - if (Derivative) Nonlinear_Iter = 1; - - /*--- Loop over the total number of grid deformation iterations. The surface - deformation can be divided into increments to help with stability. In - particular, the linear elasticity equations hold only for small deformations. ---*/ - - for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { - /*--- Initialize vector and sparse matrix ---*/ - - LinSysSol.SetValZero(); - LinSysRes.SetValZero(); - StiffMatrix.SetValZero(); - - /*--- Compute the stiffness matrix entries for all nodes/elements in the - mesh. FEA uses a finite element method discretization of the linear - elasticity equations (transfers element stiffnesses to point-to-point). ---*/ - - MinVolume = SetFEAMethodContributions_Elem(geometry, config); - - /*--- Set the boundary and volume displacements (as prescribed by the - design variable perturbations controlling the surface shape) - as a Dirichlet BC. ---*/ - - SetBoundaryDisplacements(geometry, config); - - /*--- Fix the location of any points in the domain, if requested. ---*/ - - SetDomainDisplacements(geometry, config); - - /*--- Set the boundary derivatives (overrides the actual displacements) ---*/ - - if (Derivative) { - SetBoundaryDerivatives(geometry, config, ForwardProjectionDerivative); - } - - /*--- Communicate any prescribed boundary displacements via MPI, - so that all nodes have the same solution and r.h.s. entries - across all partitions. ---*/ - - CSysMatrixComms::Initiate(LinSysSol, geometry, config); - CSysMatrixComms::Complete(LinSysSol, geometry, config); - - CSysMatrixComms::Initiate(LinSysRes, geometry, config); - CSysMatrixComms::Complete(LinSysRes, geometry, config); - - /*--- Definition of the preconditioner matrix vector multiplication, and linear solver ---*/ - - /*--- To keep legacy behavior ---*/ - System.SetToleranceType(LinearToleranceType::RELATIVE); - - /*--- If we want no derivatives or the direct derivatives, we solve the system using the - * normal matrix vector product and preconditioner. For the mesh sensitivities using - * the discrete adjoint method we solve the system using the transposed matrix. ---*/ - if (!Derivative || ((config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD) && Derivative) || - (config->GetSmoothGradient() && ForwardProjectionDerivative)) { - Tot_Iter = System.Solve(StiffMatrix, LinSysRes, LinSysSol, geometry, config); - - } else if (Derivative && (config->GetKind_SU2() == SU2_COMPONENT::SU2_DOT)) { - Tot_Iter = System.Solve_b(StiffMatrix, LinSysRes, LinSysSol, geometry, config); - } - su2double Residual = System.GetResidual(); - - /*--- Update the grid coordinates and cell volumes using the solution - of the linear system (usol contains the x, y, z displacements). ---*/ - - if (!Derivative) { - UpdateGridCoord(geometry, config); - } else { - UpdateGridCoord_Derivatives(geometry, config, ForwardProjectionDerivative); - } - if (UpdateGeo) { - UpdateDualGrid(geometry, config); - } - - if (!Derivative) { - /*--- Check for failed deformation (negative volumes). ---*/ - - ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); - - /*--- Calculate amount of nonconvex elements ---*/ - - ComputenNonconvexElements(geometry, Screen_Output); - } - - /*--- Set number of iterations in the mesh update. ---*/ - - Set_nIterMesh(Tot_Iter); - - if (rank == MASTER_NODE && Screen_Output) { - cout << "Non-linear iter.: " << iNonlinear_Iter + 1 << "/" << Nonlinear_Iter << ". Linear iter.: " << Tot_Iter - << ". "; - if (nDim == 2) - cout << "Min. area: " << MinVolume << ". Error: " << Residual << "." << endl; - else - cout << "Min. volume: " << MinVolume << ". Error: " << Residual << "." << endl; - } - } -} void CVolumetricMovement::ComputeDeforming_Element_Volume(CGeometry* geometry, su2double& MinVolume, su2double& MaxVolume, bool Screen_Output) { @@ -364,644 +208,6 @@ void CVolumetricMovement::ComputenNonconvexElements(CGeometry* geometry, bool Sc geometry->SetnNonconvexElements(nNonconvexElements); } -void CVolumetricMovement::ComputeSolid_Wall_Distance(CGeometry* geometry, CConfig* config, su2double& MinDistance, - su2double& MaxDistance) const { - unsigned long nVertex_SolidWall, ii, jj, iVertex, iPoint, pointID; - unsigned short iMarker, iDim; - su2double dist, MaxDistance_Local, MinDistance_Local; - int rankID; - - /*--- Initialize min and max distance ---*/ - - MaxDistance = -1E22; - MinDistance = 1E22; - - /*--- Compute the total number of nodes on no-slip boundaries ---*/ - - nVertex_SolidWall = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); ++iMarker) { - if (config->GetSolid_Wall(iMarker)) nVertex_SolidWall += geometry->GetnVertex(iMarker); - } - - /*--- Allocate the vectors to hold boundary node coordinates - and its local ID. ---*/ - - vector Coord_bound(nDim * nVertex_SolidWall); - vector PointIDs(nVertex_SolidWall); - - /*--- Retrieve and store the coordinates of the no-slip boundary nodes - and their local point IDs. ---*/ - - ii = 0; - jj = 0; - for (iMarker = 0; iMarker < config->GetnMarker_All(); ++iMarker) { - if (config->GetSolid_Wall(iMarker)) { - for (iVertex = 0; iVertex < geometry->GetnVertex(iMarker); ++iVertex) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - PointIDs[jj++] = iPoint; - for (iDim = 0; iDim < nDim; ++iDim) Coord_bound[ii++] = geometry->nodes->GetCoord(iPoint, iDim); - } - } - } - - /*--- Build the ADT of the boundary nodes. ---*/ - - CADTPointsOnlyClass WallADT(nDim, nVertex_SolidWall, Coord_bound.data(), PointIDs.data(), true); - - /*--- Loop over all interior mesh nodes and compute the distances to each - of the no-slip boundary nodes. Store the minimum distance to the wall - for each interior mesh node. ---*/ - - if (WallADT.IsEmpty()) { - /*--- No solid wall boundary nodes in the entire mesh. - Set the wall distance to zero for all nodes. ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); ++iPoint) geometry->nodes->SetWall_Distance(iPoint, 0.0); - } else { - /*--- Solid wall boundary nodes are present. Compute the wall - distance for all nodes. ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); ++iPoint) { - WallADT.DetermineNearestNode(geometry->nodes->GetCoord(iPoint), dist, pointID, rankID); - geometry->nodes->SetWall_Distance(iPoint, dist); - - MaxDistance = max(MaxDistance, dist); - - /*--- To discard points on the surface we use > EPS ---*/ - - if (sqrt(dist) > EPS) MinDistance = min(MinDistance, dist); - } - - MaxDistance_Local = MaxDistance; - MaxDistance = 0.0; - MinDistance_Local = MinDistance; - MinDistance = 0.0; - -#ifdef HAVE_MPI - SU2_MPI::Allreduce(&MaxDistance_Local, &MaxDistance, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); - SU2_MPI::Allreduce(&MinDistance_Local, &MinDistance, 1, MPI_DOUBLE, MPI_MIN, SU2_MPI::GetComm()); -#else - MaxDistance = MaxDistance_Local; - MinDistance = MinDistance_Local; -#endif - } -} - -su2double CVolumetricMovement::SetFEAMethodContributions_Elem(CGeometry* geometry, CConfig* config) { - unsigned short iVar, iDim, nNodes = 0, iNodes, StiffMatrix_nElem = 0; - unsigned long iElem, PointCorners[8]; - su2double **StiffMatrix_Elem = nullptr, CoordCorners[8][3]; - su2double MinVolume = 0.0, MaxVolume = 0.0, MinDistance = 0.0, MaxDistance = 0.0, ElemVolume = 0.0, - ElemDistance = 0.0; - - bool Screen_Output = config->GetDeform_Output(); - - /*--- Allocate maximum size (quadrilateral and hexahedron) ---*/ - - if (nDim == 2) - StiffMatrix_nElem = 8; - else - StiffMatrix_nElem = 24; - - StiffMatrix_Elem = new su2double*[StiffMatrix_nElem]; - for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) StiffMatrix_Elem[iVar] = new su2double[StiffMatrix_nElem]; - - /*--- Compute min volume in the entire mesh. ---*/ - - ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); - if (rank == MASTER_NODE && Screen_Output) - cout << "Min. volume: " << MinVolume << ", max. volume: " << MaxVolume << "." << endl; - - /*--- Compute the distance to the nearest surface if needed - as part of the stiffness calculation.. ---*/ - - if ((config->GetDeform_Stiffness_Type() == SOLID_WALL_DISTANCE) || (config->GetDeform_Limit() < 1E6)) { - ComputeSolid_Wall_Distance(geometry, config, MinDistance, MaxDistance); - if (rank == MASTER_NODE && Screen_Output) - cout << "Min. distance: " << MinDistance << ", max. distance: " << MaxDistance << "." << endl; - } - - /*--- Compute contributions from each element by forming the stiffness matrix (FEA) ---*/ - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++) { - if (geometry->elem[iElem]->GetVTK_Type() == TRIANGLE) nNodes = 3; - if (geometry->elem[iElem]->GetVTK_Type() == QUADRILATERAL) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == TETRAHEDRON) nNodes = 4; - if (geometry->elem[iElem]->GetVTK_Type() == PYRAMID) nNodes = 5; - if (geometry->elem[iElem]->GetVTK_Type() == PRISM) nNodes = 6; - if (geometry->elem[iElem]->GetVTK_Type() == HEXAHEDRON) nNodes = 8; - - for (iNodes = 0; iNodes < nNodes; iNodes++) { - PointCorners[iNodes] = geometry->elem[iElem]->GetNode(iNodes); - for (iDim = 0; iDim < nDim; iDim++) { - CoordCorners[iNodes][iDim] = geometry->nodes->GetCoord(PointCorners[iNodes], iDim); - } - } - - /*--- Extract Element volume and distance to compute the stiffness ---*/ - - ElemVolume = geometry->elem[iElem]->GetVolume(); - - if ((config->GetDeform_Stiffness_Type() == SOLID_WALL_DISTANCE)) { - ElemDistance = 0.0; - for (iNodes = 0; iNodes < nNodes; iNodes++) - ElemDistance += geometry->nodes->GetWall_Distance(PointCorners[iNodes]); - ElemDistance = ElemDistance / (su2double)nNodes; - } - - if (nDim == 2) - SetFEA_StiffMatrix2D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, ElemVolume, - ElemDistance); - if (nDim == 3) - SetFEA_StiffMatrix3D(geometry, config, StiffMatrix_Elem, PointCorners, CoordCorners, nNodes, ElemVolume, - ElemDistance); - - AddFEA_StiffMatrix(geometry, StiffMatrix_Elem, PointCorners, nNodes); - } - - /*--- Deallocate memory and exit ---*/ - - for (iVar = 0; iVar < StiffMatrix_nElem; iVar++) delete[] StiffMatrix_Elem[iVar]; - delete[] StiffMatrix_Elem; - - return MinVolume; -} - -su2double CVolumetricMovement::ShapeFunc_Triangle(su2double Xi, su2double Eta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]) { - int i, j, k; - su2double c0, c1, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = Xi; - DShapeFunction[1][3] = Eta; - DShapeFunction[2][3] = 1 - Xi - Eta; - - /*--- dN/d xi, dN/d eta ---*/ - - DShapeFunction[0][0] = 1.0; - DShapeFunction[0][1] = 0.0; - DShapeFunction[1][0] = 0.0; - DShapeFunction[1][1] = 1.0; - DShapeFunction[2][0] = -1.0; - DShapeFunction[2][1] = -1.0; - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 3; k++) { - xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]; - ad[0][1] = -xs[0][1]; - ad[1][0] = -xs[1][0]; - ad[1][1] = xs[0][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = ad[0][0] * ad[1][1] - ad[0][1] * ad[1][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = ad[i][j] / xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 3; k++) { - c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1]; // dN/dx - c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1]; // dN/dy - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - } - - return xsj; -} - -su2double CVolumetricMovement::ShapeFunc_Quadrilateral(su2double Xi, su2double Eta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]) { - int i, j, k; - su2double c0, c1, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.25 * (1.0 - Xi) * (1.0 - Eta); - DShapeFunction[1][3] = 0.25 * (1.0 + Xi) * (1.0 - Eta); - DShapeFunction[2][3] = 0.25 * (1.0 + Xi) * (1.0 + Eta); - DShapeFunction[3][3] = 0.25 * (1.0 - Xi) * (1.0 + Eta); - - /*--- dN/d xi, dN/d eta ---*/ - - DShapeFunction[0][0] = -0.25 * (1.0 - Eta); - DShapeFunction[0][1] = -0.25 * (1.0 - Xi); - DShapeFunction[1][0] = 0.25 * (1.0 - Eta); - DShapeFunction[1][1] = -0.25 * (1.0 + Xi); - DShapeFunction[2][0] = 0.25 * (1.0 + Eta); - DShapeFunction[2][1] = 0.25 * (1.0 + Xi); - DShapeFunction[3][0] = -0.25 * (1.0 + Eta); - DShapeFunction[3][1] = 0.25 * (1.0 - Xi); - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 4; k++) { - xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1]; - ad[0][1] = -xs[0][1]; - ad[1][0] = -xs[1][0]; - ad[1][1] = xs[0][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = ad[0][0] * ad[1][1] - ad[0][1] * ad[1][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 2; i++) { - for (j = 0; j < 2; j++) { - xs[i][j] = ad[i][j] / xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 4; k++) { - c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1]; // dN/dx - c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1]; // dN/dy - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - } - - return xsj; -} - -su2double CVolumetricMovement::ShapeFunc_Tetra(su2double Xi, su2double Eta, su2double Zeta, - su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = Xi; - DShapeFunction[1][3] = Zeta; - DShapeFunction[2][3] = 1.0 - Xi - Eta - Zeta; - DShapeFunction[3][3] = Eta; - - /*--- dN/d xi, dN/d eta, dN/d zeta ---*/ - - DShapeFunction[0][0] = 1.0; - DShapeFunction[0][1] = 0.0; - DShapeFunction[0][2] = 0.0; - DShapeFunction[1][0] = 0.0; - DShapeFunction[1][1] = 0.0; - DShapeFunction[1][2] = 1.0; - DShapeFunction[2][0] = -1.0; - DShapeFunction[2][1] = -1.0; - DShapeFunction[2][2] = -1.0; - DShapeFunction[3][0] = 0.0; - DShapeFunction[3][1] = 1.0; - DShapeFunction[3][2] = 0.0; - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 4; k++) { - xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; - ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; - ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; - ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; - ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; - ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; - ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; - ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; - ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j] / xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 4; k++) { - c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; -} - -su2double CVolumetricMovement::ShapeFunc_Pyram(su2double Xi, su2double Eta, su2double Zeta, - su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.25 * (-Xi + Eta + Zeta - 1.0) * (-Xi - Eta + Zeta - 1.0) / (1.0 - Zeta); - DShapeFunction[1][3] = 0.25 * (-Xi - Eta + Zeta - 1.0) * (Xi - Eta + Zeta - 1.0) / (1.0 - Zeta); - DShapeFunction[2][3] = 0.25 * (Xi + Eta + Zeta - 1.0) * (Xi - Eta + Zeta - 1.0) / (1.0 - Zeta); - DShapeFunction[3][3] = 0.25 * (Xi + Eta + Zeta - 1.0) * (-Xi + Eta + Zeta - 1.0) / (1.0 - Zeta); - DShapeFunction[4][3] = Zeta; - - /*--- dN/d xi ---*/ - - DShapeFunction[0][0] = 0.5 * (Zeta - Xi - 1.0) / (Zeta - 1.0); - DShapeFunction[1][0] = 0.5 * Xi / (Zeta - 1.0); - DShapeFunction[2][0] = 0.5 * (1.0 - Zeta - Xi) / (Zeta - 1.0); - DShapeFunction[3][0] = DShapeFunction[1][0]; - DShapeFunction[4][0] = 0.0; - - /*--- dN/d eta ---*/ - - DShapeFunction[0][1] = 0.5 * Eta / (Zeta - 1.0); - DShapeFunction[1][1] = 0.5 * (Zeta - Eta - 1.0) / (Zeta - 1.0); - DShapeFunction[2][1] = DShapeFunction[0][1]; - DShapeFunction[3][1] = 0.5 * (1.0 - Zeta - Eta) / (Zeta - 1.0); - DShapeFunction[4][1] = 0.0; - - /*--- dN/d zeta ---*/ - - DShapeFunction[0][2] = 0.25 * (-1.0 + 2.0 * Zeta - Zeta * Zeta - Eta * Eta + Xi * Xi) / ((1.0 - Zeta) * (1.0 - Zeta)); - DShapeFunction[1][2] = 0.25 * (-1.0 + 2.0 * Zeta - Zeta * Zeta + Eta * Eta - Xi * Xi) / ((1.0 - Zeta) * (1.0 - Zeta)); - DShapeFunction[2][2] = DShapeFunction[0][2]; - DShapeFunction[3][2] = DShapeFunction[1][2]; - DShapeFunction[4][2] = 1.0; - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 5; k++) { - xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; - ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; - ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; - ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; - ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; - ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; - ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; - ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; - ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j] / xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 5; k++) { - c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; -} - -su2double CVolumetricMovement::ShapeFunc_Prism(su2double Xi, su2double Eta, su2double Zeta, - su2double CoordCorners[8][3], su2double DShapeFunction[8][4]) { - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.5 * Eta * (1.0 - Xi); - DShapeFunction[1][3] = 0.5 * Zeta * (1.0 - Xi); - DShapeFunction[2][3] = 0.5 * (1.0 - Eta - Zeta) * (1.0 - Xi); - DShapeFunction[3][3] = 0.5 * Eta * (Xi + 1.0); - DShapeFunction[4][3] = 0.5 * Zeta * (Xi + 1.0); - DShapeFunction[5][3] = 0.5 * (1.0 - Eta - Zeta) * (Xi + 1.0); - - /*--- dN/d Xi, dN/d Eta, dN/d Zeta ---*/ - - DShapeFunction[0][0] = -0.5 * Eta; - DShapeFunction[0][1] = 0.5 * (1.0 - Xi); - DShapeFunction[0][2] = 0.0; - DShapeFunction[1][0] = -0.5 * Zeta; - DShapeFunction[1][1] = 0.0; - DShapeFunction[1][2] = 0.5 * (1.0 - Xi); - DShapeFunction[2][0] = -0.5 * (1.0 - Eta - Zeta); - DShapeFunction[2][1] = -0.5 * (1.0 - Xi); - DShapeFunction[2][2] = -0.5 * (1.0 - Xi); - DShapeFunction[3][0] = 0.5 * Eta; - DShapeFunction[3][1] = 0.5 * (Xi + 1.0); - DShapeFunction[3][2] = 0.0; - DShapeFunction[4][0] = 0.5 * Zeta; - DShapeFunction[4][1] = 0.0; - DShapeFunction[4][2] = 0.5 * (Xi + 1.0); - DShapeFunction[5][0] = 0.5 * (1.0 - Eta - Zeta); - DShapeFunction[5][1] = -0.5 * (Xi + 1.0); - DShapeFunction[5][2] = -0.5 * (Xi + 1.0); - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 6; k++) { - xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; - ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; - ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; - ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; - ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; - ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; - ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; - ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; - ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; - - /*--- Jacobian inverse ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j] / xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 6; k++) { - c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; -} - -su2double CVolumetricMovement::ShapeFunc_Hexa(su2double Xi, su2double Eta, su2double Zeta, su2double CoordCorners[8][3], - su2double DShapeFunction[8][4]) { - int i, j, k; - su2double c0, c1, c2, xsj; - su2double xs[3][3], ad[3][3]; - - /*--- Shape functions ---*/ - - DShapeFunction[0][3] = 0.125 * (1.0 - Xi) * (1.0 - Eta) * (1.0 - Zeta); - DShapeFunction[1][3] = 0.125 * (1.0 + Xi) * (1.0 - Eta) * (1.0 - Zeta); - DShapeFunction[2][3] = 0.125 * (1.0 + Xi) * (1.0 + Eta) * (1.0 - Zeta); - DShapeFunction[3][3] = 0.125 * (1.0 - Xi) * (1.0 + Eta) * (1.0 - Zeta); - DShapeFunction[4][3] = 0.125 * (1.0 - Xi) * (1.0 - Eta) * (1.0 + Zeta); - DShapeFunction[5][3] = 0.125 * (1.0 + Xi) * (1.0 - Eta) * (1.0 + Zeta); - DShapeFunction[6][3] = 0.125 * (1.0 + Xi) * (1.0 + Eta) * (1.0 + Zeta); - DShapeFunction[7][3] = 0.125 * (1.0 - Xi) * (1.0 + Eta) * (1.0 + Zeta); - - /*--- dN/d xi ---*/ - - DShapeFunction[0][0] = -0.125 * (1.0 - Eta) * (1.0 - Zeta); - DShapeFunction[1][0] = 0.125 * (1.0 - Eta) * (1.0 - Zeta); - DShapeFunction[2][0] = 0.125 * (1.0 + Eta) * (1.0 - Zeta); - DShapeFunction[3][0] = -0.125 * (1.0 + Eta) * (1.0 - Zeta); - DShapeFunction[4][0] = -0.125 * (1.0 - Eta) * (1.0 + Zeta); - DShapeFunction[5][0] = 0.125 * (1.0 - Eta) * (1.0 + Zeta); - DShapeFunction[6][0] = 0.125 * (1.0 + Eta) * (1.0 + Zeta); - DShapeFunction[7][0] = -0.125 * (1.0 + Eta) * (1.0 + Zeta); - - /*--- dN/d eta ---*/ - - DShapeFunction[0][1] = -0.125 * (1.0 - Xi) * (1.0 - Zeta); - DShapeFunction[1][1] = -0.125 * (1.0 + Xi) * (1.0 - Zeta); - DShapeFunction[2][1] = 0.125 * (1.0 + Xi) * (1.0 - Zeta); - DShapeFunction[3][1] = 0.125 * (1.0 - Xi) * (1.0 - Zeta); - DShapeFunction[4][1] = -0.125 * (1.0 - Xi) * (1.0 + Zeta); - DShapeFunction[5][1] = -0.125 * (1.0 + Xi) * (1.0 + Zeta); - DShapeFunction[6][1] = 0.125 * (1.0 + Xi) * (1.0 + Zeta); - DShapeFunction[7][1] = 0.125 * (1.0 - Xi) * (1.0 + Zeta); - - /*--- dN/d zeta ---*/ - - DShapeFunction[0][2] = -0.125 * (1.0 - Xi) * (1.0 - Eta); - DShapeFunction[1][2] = -0.125 * (1.0 + Xi) * (1.0 - Eta); - DShapeFunction[2][2] = -0.125 * (1.0 + Xi) * (1.0 + Eta); - DShapeFunction[3][2] = -0.125 * (1.0 - Xi) * (1.0 + Eta); - DShapeFunction[4][2] = 0.125 * (1.0 - Xi) * (1.0 - Eta); - DShapeFunction[5][2] = 0.125 * (1.0 + Xi) * (1.0 - Eta); - DShapeFunction[6][2] = 0.125 * (1.0 + Xi) * (1.0 + Eta); - DShapeFunction[7][2] = 0.125 * (1.0 - Xi) * (1.0 + Eta); - - /*--- Jacobian transformation ---*/ - - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = 0.0; - for (k = 0; k < 8; k++) { - xs[i][j] = xs[i][j] + CoordCorners[k][j] * DShapeFunction[k][i]; - } - } - } - - /*--- Adjoint to Jacobian ---*/ - - ad[0][0] = xs[1][1] * xs[2][2] - xs[1][2] * xs[2][1]; - ad[0][1] = xs[0][2] * xs[2][1] - xs[0][1] * xs[2][2]; - ad[0][2] = xs[0][1] * xs[1][2] - xs[0][2] * xs[1][1]; - ad[1][0] = xs[1][2] * xs[2][0] - xs[1][0] * xs[2][2]; - ad[1][1] = xs[0][0] * xs[2][2] - xs[0][2] * xs[2][0]; - ad[1][2] = xs[0][2] * xs[1][0] - xs[0][0] * xs[1][2]; - ad[2][0] = xs[1][0] * xs[2][1] - xs[1][1] * xs[2][0]; - ad[2][1] = xs[0][1] * xs[2][0] - xs[0][0] * xs[2][1]; - ad[2][2] = xs[0][0] * xs[1][1] - xs[0][1] * xs[1][0]; - - /*--- Determinant of Jacobian ---*/ - - xsj = xs[0][0] * ad[0][0] + xs[0][1] * ad[1][0] + xs[0][2] * ad[2][0]; - - /*--- Jacobian inverse ---*/ - for (i = 0; i < 3; i++) { - for (j = 0; j < 3; j++) { - xs[i][j] = ad[i][j] / xsj; - } - } - - /*--- Derivatives with repect to global coordinates ---*/ - - for (k = 0; k < 8; k++) { - c0 = xs[0][0] * DShapeFunction[k][0] + xs[0][1] * DShapeFunction[k][1] + xs[0][2] * DShapeFunction[k][2]; // dN/dx - c1 = xs[1][0] * DShapeFunction[k][0] + xs[1][1] * DShapeFunction[k][1] + xs[1][2] * DShapeFunction[k][2]; // dN/dy - c2 = xs[2][0] * DShapeFunction[k][0] + xs[2][1] * DShapeFunction[k][1] + xs[2][2] * DShapeFunction[k][2]; // dN/dz - DShapeFunction[k][0] = c0; // store dN/dx instead of dN/d xi - DShapeFunction[k][1] = c1; // store dN/dy instead of dN/d eta - DShapeFunction[k][2] = c2; // store dN/dz instead of dN/d zeta - } - - return xsj; -} su2double CVolumetricMovement::GetTriangle_Area(su2double CoordCorners[8][3]) const { unsigned short iDim; @@ -1275,651 +481,8 @@ su2double CVolumetricMovement::GetHexa_Volume(su2double CoordCorners[8][3]) cons return Volume; } -void CVolumetricMovement::SetFEA_StiffMatrix2D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, - unsigned long PointCorners[8], su2double CoordCorners[8][3], - unsigned short nNodes, su2double ElemVolume, su2double ElemDistance) { - su2double B_Matrix[3][8], D_Matrix[3][3], Aux_Matrix[8][3]; - su2double Xi = 0.0, Eta = 0.0, Det = 0.0, E = 1 / EPS, Lambda = 0.0, Mu = 0.0, Nu = 0.0; - unsigned short iNode, iVar, jVar, kVar, iGauss, nGauss = 0; - su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; - su2double Location[4][3], Weight[4]; - unsigned short nVar = geometry->GetnDim(); - - for (iVar = 0; iVar < nNodes * nVar; iVar++) { - for (jVar = 0; jVar < nNodes * nVar; jVar++) { - StiffMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Integration formulae from "Shape functions and points of - integration of the Résumé" by Josselin DELMAS (2013) ---*/ - - /*--- Triangle. Nodes of numerical integration at 1 point (order 1). ---*/ - - if (nNodes == 3) { - nGauss = 1; - Location[0][0] = 0.333333333333333; - Location[0][1] = 0.333333333333333; - Weight[0] = 0.5; - } - - /*--- Quadrilateral. Nodes of numerical integration at 4 points (order 2). ---*/ - - if (nNodes == 4) { - nGauss = 4; - Location[0][0] = -0.577350269189626; - Location[0][1] = -0.577350269189626; - Weight[0] = 1.0; - Location[1][0] = 0.577350269189626; - Location[1][1] = -0.577350269189626; - Weight[1] = 1.0; - Location[2][0] = 0.577350269189626; - Location[2][1] = 0.577350269189626; - Weight[2] = 1.0; - Location[3][0] = -0.577350269189626; - Location[3][1] = 0.577350269189626; - Weight[3] = 1.0; - } - - for (iGauss = 0; iGauss < nGauss; iGauss++) { - Xi = Location[iGauss][0]; - Eta = Location[iGauss][1]; - - if (nNodes == 3) Det = ShapeFunc_Triangle(Xi, Eta, CoordCorners, DShapeFunction); - if (nNodes == 4) Det = ShapeFunc_Quadrilateral(Xi, Eta, CoordCorners, DShapeFunction); - - /*--- Compute the B Matrix ---*/ - - for (iVar = 0; iVar < 3; iVar++) - for (jVar = 0; jVar < nNodes * nVar; jVar++) B_Matrix[iVar][jVar] = 0.0; - - for (iNode = 0; iNode < nNodes; iNode++) { - B_Matrix[0][0 + iNode * nVar] = DShapeFunction[iNode][0]; - B_Matrix[1][1 + iNode * nVar] = DShapeFunction[iNode][1]; - - B_Matrix[2][0 + iNode * nVar] = DShapeFunction[iNode][1]; - B_Matrix[2][1 + iNode * nVar] = DShapeFunction[iNode][0]; - } - - /*--- Impose a type of stiffness for each element ---*/ - - switch (config->GetDeform_Stiffness_Type()) { - case INVERSE_VOLUME: - E = 1.0 / ElemVolume; - break; - case SOLID_WALL_DISTANCE: - E = 1.0 / ElemDistance; - break; - case CONSTANT_STIFFNESS: - E = 1.0 / EPS; - break; - } - - Nu = config->GetDeform_Coeff(); - Mu = E / (2.0 * (1.0 + Nu)); - Lambda = Nu * E / ((1.0 + Nu) * (1.0 - 2.0 * Nu)); - - /*--- Compute the D Matrix (for plane strain and 3-D)---*/ - - D_Matrix[0][0] = Lambda + 2.0 * Mu; - D_Matrix[0][1] = Lambda; - D_Matrix[0][2] = 0.0; - D_Matrix[1][0] = Lambda; - D_Matrix[1][1] = Lambda + 2.0 * Mu; - D_Matrix[1][2] = 0.0; - D_Matrix[2][0] = 0.0; - D_Matrix[2][1] = 0.0; - D_Matrix[2][2] = Mu; - - /*--- Compute the BT.D Matrix ---*/ - - for (iVar = 0; iVar < nNodes * nVar; iVar++) { - for (jVar = 0; jVar < 3; jVar++) { - Aux_Matrix[iVar][jVar] = 0.0; - for (kVar = 0; kVar < 3; kVar++) Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar] * D_Matrix[kVar][jVar]; - } - } - - /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original - matrix using Gauss integration ---*/ - - for (iVar = 0; iVar < nNodes * nVar; iVar++) { - for (jVar = 0; jVar < nNodes * nVar; jVar++) { - for (kVar = 0; kVar < 3; kVar++) { - StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar] * B_Matrix[kVar][jVar] * fabs(Det); - } - } - } - } -} - -void CVolumetricMovement::SetFEA_StiffMatrix3D(CGeometry* geometry, CConfig* config, su2double** StiffMatrix_Elem, - unsigned long PointCorners[8], su2double CoordCorners[8][3], - unsigned short nNodes, su2double ElemVolume, su2double ElemDistance) { - su2double B_Matrix[6][24], - D_Matrix[6][6] = {{0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0, 0.0, 0.0}}, - Aux_Matrix[24][6]; - su2double Xi = 0.0, Eta = 0.0, Zeta = 0.0, Det = 0.0, Mu = 0.0, E = 0.0, Lambda = 0.0, Nu = 0.0; - unsigned short iNode, iVar, jVar, kVar, iGauss, nGauss = 0; - su2double DShapeFunction[8][4] = {{0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}, - {0.0, 0.0, 0.0, 0.0}, {0.0, 0.0, 0.0, 0.0}}; - su2double Location[8][3], Weight[8]; - unsigned short nVar = geometry->GetnDim(); - - for (iVar = 0; iVar < nNodes * nVar; iVar++) { - for (jVar = 0; jVar < nNodes * nVar; jVar++) { - StiffMatrix_Elem[iVar][jVar] = 0.0; - } - } - - /*--- Integration formulae from "Shape functions and points of - integration of the Résumé" by Josselin Delmas (2013) ---*/ - - /*--- Tetrahedrons. Nodes of numerical integration at 1 point (order 1). ---*/ - - if (nNodes == 4) { - nGauss = 1; - Location[0][0] = 0.25; - Location[0][1] = 0.25; - Location[0][2] = 0.25; - Weight[0] = 0.166666666666666; - } - - /*--- Pyramids. Nodes numerical integration at 5 points. ---*/ - - if (nNodes == 5) { - nGauss = 5; - Location[0][0] = 0.5; - Location[0][1] = 0.0; - Location[0][2] = 0.1531754163448146; - Weight[0] = 0.133333333333333; - Location[1][0] = 0.0; - Location[1][1] = 0.5; - Location[1][2] = 0.1531754163448146; - Weight[1] = 0.133333333333333; - Location[2][0] = -0.5; - Location[2][1] = 0.0; - Location[2][2] = 0.1531754163448146; - Weight[2] = 0.133333333333333; - Location[3][0] = 0.0; - Location[3][1] = -0.5; - Location[3][2] = 0.1531754163448146; - Weight[3] = 0.133333333333333; - Location[4][0] = 0.0; - Location[4][1] = 0.0; - Location[4][2] = 0.6372983346207416; - Weight[4] = 0.133333333333333; - } - - /*--- Prism. Nodes of numerical integration at 6 points (order 3 in Xi, order 2 in Eta and Mu ). ---*/ - - if (nNodes == 6) { - nGauss = 6; - Location[0][0] = -0.577350269189626; - Location[0][1] = 0.166666666666667; - Location[0][2] = 0.166666666666667; - Weight[0] = 0.166666666666667; - Location[1][0] = -0.577350269189626; - Location[1][1] = 0.666666666666667; - Location[1][2] = 0.166666666666667; - Weight[1] = 0.166666666666667; - Location[2][0] = -0.577350269189626; - Location[2][1] = 0.166666666666667; - Location[2][2] = 0.666666666666667; - Weight[2] = 0.166666666666667; - Location[3][0] = 0.577350269189626; - Location[3][1] = 0.166666666666667; - Location[3][2] = 0.166666666666667; - Weight[3] = 0.166666666666667; - Location[4][0] = 0.577350269189626; - Location[4][1] = 0.666666666666667; - Location[4][2] = 0.166666666666667; - Weight[4] = 0.166666666666667; - Location[5][0] = 0.577350269189626; - Location[5][1] = 0.166666666666667; - Location[5][2] = 0.666666666666667; - Weight[5] = 0.166666666666667; - } - - /*--- Hexahedrons. Nodes of numerical integration at 6 points (order 3). ---*/ - - if (nNodes == 8) { - nGauss = 8; - Location[0][0] = -0.577350269189626; - Location[0][1] = -0.577350269189626; - Location[0][2] = -0.577350269189626; - Weight[0] = 1.0; - Location[1][0] = -0.577350269189626; - Location[1][1] = -0.577350269189626; - Location[1][2] = 0.577350269189626; - Weight[1] = 1.0; - Location[2][0] = -0.577350269189626; - Location[2][1] = 0.577350269189626; - Location[2][2] = -0.577350269189626; - Weight[2] = 1.0; - Location[3][0] = -0.577350269189626; - Location[3][1] = 0.577350269189626; - Location[3][2] = 0.577350269189626; - Weight[3] = 1.0; - Location[4][0] = 0.577350269189626; - Location[4][1] = -0.577350269189626; - Location[4][2] = -0.577350269189626; - Weight[4] = 1.0; - Location[5][0] = 0.577350269189626; - Location[5][1] = -0.577350269189626; - Location[5][2] = 0.577350269189626; - Weight[5] = 1.0; - Location[6][0] = 0.577350269189626; - Location[6][1] = 0.577350269189626; - Location[6][2] = -0.577350269189626; - Weight[6] = 1.0; - Location[7][0] = 0.577350269189626; - Location[7][1] = 0.577350269189626; - Location[7][2] = 0.577350269189626; - Weight[7] = 1.0; - } - - for (iGauss = 0; iGauss < nGauss; iGauss++) { - Xi = Location[iGauss][0]; - Eta = Location[iGauss][1]; - Zeta = Location[iGauss][2]; - - if (nNodes == 4) Det = ShapeFunc_Tetra(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - if (nNodes == 5) Det = ShapeFunc_Pyram(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - if (nNodes == 6) Det = ShapeFunc_Prism(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - if (nNodes == 8) Det = ShapeFunc_Hexa(Xi, Eta, Zeta, CoordCorners, DShapeFunction); - - /*--- Compute the B Matrix ---*/ - - for (iVar = 0; iVar < 6; iVar++) - for (jVar = 0; jVar < nNodes * nVar; jVar++) B_Matrix[iVar][jVar] = 0.0; - - for (iNode = 0; iNode < nNodes; iNode++) { - B_Matrix[0][0 + iNode * nVar] = DShapeFunction[iNode][0]; - B_Matrix[1][1 + iNode * nVar] = DShapeFunction[iNode][1]; - B_Matrix[2][2 + iNode * nVar] = DShapeFunction[iNode][2]; - - B_Matrix[3][0 + iNode * nVar] = DShapeFunction[iNode][1]; - B_Matrix[3][1 + iNode * nVar] = DShapeFunction[iNode][0]; - - B_Matrix[4][1 + iNode * nVar] = DShapeFunction[iNode][2]; - B_Matrix[4][2 + iNode * nVar] = DShapeFunction[iNode][1]; - - B_Matrix[5][0 + iNode * nVar] = DShapeFunction[iNode][2]; - B_Matrix[5][2 + iNode * nVar] = DShapeFunction[iNode][0]; - } - - /*--- Impose a type of stiffness for each element ---*/ - - switch (config->GetDeform_Stiffness_Type()) { - case INVERSE_VOLUME: - E = 1.0 / ElemVolume; - break; - case SOLID_WALL_DISTANCE: - E = 1.0 / ElemDistance; - break; - case CONSTANT_STIFFNESS: - E = 1.0 / EPS; - break; - } - - Nu = config->GetDeform_Coeff(); - Mu = E / (2.0 * (1.0 + Nu)); - Lambda = Nu * E / ((1.0 + Nu) * (1.0 - 2.0 * Nu)); - - /*--- Compute the D Matrix (for plane strain and 3-D)---*/ - - D_Matrix[0][0] = Lambda + 2.0 * Mu; - D_Matrix[0][1] = Lambda; - D_Matrix[0][2] = Lambda; - D_Matrix[1][0] = Lambda; - D_Matrix[1][1] = Lambda + 2.0 * Mu; - D_Matrix[1][2] = Lambda; - D_Matrix[2][0] = Lambda; - D_Matrix[2][1] = Lambda; - D_Matrix[2][2] = Lambda + 2.0 * Mu; - D_Matrix[3][3] = Mu; - D_Matrix[4][4] = Mu; - D_Matrix[5][5] = Mu; - - /*--- Compute the BT.D Matrix ---*/ - - for (iVar = 0; iVar < nNodes * nVar; iVar++) { - for (jVar = 0; jVar < 6; jVar++) { - Aux_Matrix[iVar][jVar] = 0.0; - for (kVar = 0; kVar < 6; kVar++) Aux_Matrix[iVar][jVar] += B_Matrix[kVar][iVar] * D_Matrix[kVar][jVar]; - } - } - - /*--- Compute the BT.D.B Matrix (stiffness matrix), and add to the original - matrix using Gauss integration ---*/ - - for (iVar = 0; iVar < nNodes * nVar; iVar++) { - for (jVar = 0; jVar < nNodes * nVar; jVar++) { - for (kVar = 0; kVar < 6; kVar++) { - StiffMatrix_Elem[iVar][jVar] += Weight[iGauss] * Aux_Matrix[iVar][kVar] * B_Matrix[kVar][jVar] * fabs(Det); - } - } - } - } -} - -void CVolumetricMovement::AddFEA_StiffMatrix(CGeometry* geometry, su2double** StiffMatrix_Elem, - unsigned long PointCorners[8], unsigned short nNodes) { - unsigned short iVar, jVar, iDim, jDim; - - unsigned short nVar = geometry->GetnDim(); - - su2double** StiffMatrix_Node; - StiffMatrix_Node = new su2double*[nVar]; - for (iVar = 0; iVar < nVar; iVar++) StiffMatrix_Node[iVar] = new su2double[nVar]; - - for (iVar = 0; iVar < nVar; iVar++) - for (jVar = 0; jVar < nVar; jVar++) StiffMatrix_Node[iVar][jVar] = 0.0; - - /*--- Transform the stiffness matrix for the hexahedral element into the - contributions for the individual nodes relative to each other. ---*/ - - for (iVar = 0; iVar < nNodes; iVar++) { - for (jVar = 0; jVar < nNodes; jVar++) { - for (iDim = 0; iDim < nVar; iDim++) { - for (jDim = 0; jDim < nVar; jDim++) { - StiffMatrix_Node[iDim][jDim] = StiffMatrix_Elem[(iVar * nVar) + iDim][(jVar * nVar) + jDim]; - } - } - - StiffMatrix.AddBlock(PointCorners[iVar], PointCorners[jVar], StiffMatrix_Node); - } - } - - /*--- Deallocate memory and exit ---*/ - - for (iVar = 0; iVar < nVar; iVar++) delete[] StiffMatrix_Node[iVar]; - delete[] StiffMatrix_Node; -} - -void CVolumetricMovement::SetBoundaryDisplacements(CGeometry* geometry, CConfig* config) { - unsigned short iDim, nDim = geometry->GetnDim(), iMarker, axis = 0; - unsigned long iPoint, total_index, iVertex; - su2double *VarCoord, MeanCoord[3] = {0.0, 0.0, 0.0}, VarIncrement = 1.0; - - /*--- Get the SU2 module. SU2_CFD will use this routine for dynamically - deforming meshes (MARKER_MOVING), while SU2_DEF will use it for deforming - meshes after imposing design variable surface deformations (DV_MARKER). ---*/ - - SU2_COMPONENT Kind_SU2 = config->GetKind_SU2(); - - /*--- If requested (no by default) impose the surface deflections in - increments and solve the grid deformation equations iteratively with - successive small deformations. ---*/ - - VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); - - /*--- As initialization, set to zero displacements of all the surfaces except the symmetry - plane (which is treated specially, see below), internal and the send-receive boundaries ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_KindBC(iMarker) != SYMMETRY_PLANE) && - (config->GetMarker_All_KindBC(iMarker) != SEND_RECEIVE) && - (config->GetMarker_All_KindBC(iMarker) != INTERNAL_BOUNDARY))) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Set the known displacements, note that some points of the moving surfaces - could be on on the symmetry plane, we should specify DeleteValsRowi again (just in case) ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (((config->GetMarker_All_Moving(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_DEF)) || - ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD) && - (config->GetMarker_All_DV(iMarker) == YES)) || - ((config->GetMarker_All_DV(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_DOT))) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Set to zero displacements of the normal component for the symmetry plane condition ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_KindBC(iMarker) == SYMMETRY_PLANE)) { - su2double* Coord_0 = nullptr; - - for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = 0.0; - - /*--- Store the coord of the first point to help identify the axis. ---*/ - - iPoint = geometry->vertex[iMarker][0]->GetNode(); - Coord_0 = geometry->nodes->GetCoord(iPoint); - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->nodes->GetCoord(iPoint); - for (iDim = 0; iDim < nDim; iDim++) - MeanCoord[iDim] += (VarCoord[iDim] - Coord_0[iDim]) * (VarCoord[iDim] - Coord_0[iDim]); - } - for (iDim = 0; iDim < nDim; iDim++) MeanCoord[iDim] = sqrt(MeanCoord[iDim]); - if (nDim == 3) { - if ((MeanCoord[0] <= MeanCoord[1]) && (MeanCoord[0] <= MeanCoord[2])) axis = 0; - if ((MeanCoord[1] <= MeanCoord[0]) && (MeanCoord[1] <= MeanCoord[2])) axis = 1; - if ((MeanCoord[2] <= MeanCoord[0]) && (MeanCoord[2] <= MeanCoord[1])) axis = 2; - } else { - if ((MeanCoord[0] <= MeanCoord[1])) axis = 0; - if ((MeanCoord[1] <= MeanCoord[0])) axis = 1; - } - - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - total_index = iPoint * nDim + axis; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - - /*--- Don't move the nearfield plane ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetMarker_All_KindBC(iMarker) == NEARFIELD_BOUNDARY) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Move the FSI interfaces ---*/ - - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_ZoneInterface(iMarker) == YES) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - LinSysSol[total_index] = SU2_TYPE::GetValue(VarCoord[iDim] * VarIncrement); - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } -} - -void CVolumetricMovement::SetBoundaryDerivatives(CGeometry* geometry, CConfig* config, - bool ForwardProjectionDerivative) { - unsigned short iDim, iMarker; - unsigned long iPoint, total_index, iVertex; - - su2double* VarCoord; - SU2_COMPONENT Kind_SU2 = config->GetKind_SU2(); - if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_DV(iMarker) == YES)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - VarCoord = geometry->vertex[iMarker][iVertex]->GetVarCoord(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); - LinSysSol[total_index] = SU2_TYPE::GetDerivative(VarCoord[iDim]); - } - } - } - } - if (LinSysRes.norm() == 0.0) cout << "Warning: Derivatives are zero!" << endl; - } else if ((Kind_SU2 == SU2_COMPONENT::SU2_DOT) && !ForwardProjectionDerivative) { - for (iPoint = 0; iPoint < nPoint; iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); - LinSysSol[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); - } - } - } else if (config->GetSmoothGradient() && ForwardProjectionDerivative) { - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if ((config->GetMarker_All_DV(iMarker) == YES)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); - LinSysSol[total_index] = SU2_TYPE::GetValue(geometry->GetSensitivity(iPoint, iDim)); - } - } - } - } - if (LinSysRes.norm() == 0.0) cout << "Warning: Derivatives are zero!" << endl; - } -} - -void CVolumetricMovement::UpdateGridCoord_Derivatives(CGeometry* geometry, CConfig* config, - bool ForwardProjectionDerivative) { - unsigned short iDim, iMarker; - unsigned long iPoint, total_index, iVertex; - auto* new_coord = new su2double[3]; - - SU2_COMPONENT Kind_SU2 = config->GetKind_SU2(); - - /*--- Update derivatives of the grid coordinates using the solution of the linear system - after grid deformation (LinSysSol contains the derivatives of the x, y, z displacements). ---*/ - if ((config->GetDirectDiff() == D_DESIGN) && (Kind_SU2 == SU2_COMPONENT::SU2_CFD)) { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - new_coord[0] = 0.0; - new_coord[1] = 0.0; - new_coord[2] = 0.0; - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - new_coord[iDim] = geometry->nodes->GetCoord(iPoint, iDim); - SU2_TYPE::SetDerivative(new_coord[iDim], SU2_TYPE::GetValue(LinSysSol[total_index])); - } - geometry->nodes->SetCoord(iPoint, new_coord); - } - } else if ((Kind_SU2 == SU2_COMPONENT::SU2_DOT) && !ForwardProjectionDerivative) { - // need to reset here, since we read out the whole vector, but are only interested in boundary derivatives. - if (config->GetSmoothGradient()) { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - geometry->SetSensitivity(iPoint, iDim, 0.0); - } - } - } - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - if (config->GetSolid_Wall(iMarker) || (config->GetMarker_All_DV(iMarker) == YES)) { - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { - iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); - if (geometry->nodes->GetDomain(iPoint)) { - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - geometry->SetSensitivity(iPoint, iDim, LinSysSol[total_index]); - } - } - } - } - } - } else if (config->GetSmoothGradient() && ForwardProjectionDerivative) { - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - geometry->SetSensitivity(iPoint, iDim, LinSysSol[total_index]); - } - } - } - - delete[] new_coord; -} - -void CVolumetricMovement::SetDomainDisplacements(CGeometry* geometry, CConfig* config) { - unsigned short iDim, nDim = geometry->GetnDim(); - unsigned long iPoint, total_index; - - if (config->GetHold_GridFixed()) { - auto MinCoordValues = config->GetHold_GridFixed_Coord(); - auto MaxCoordValues = &config->GetHold_GridFixed_Coord()[3]; - - /*--- Set to zero displacements of all the points that are not going to be moved - except the surfaces ---*/ - - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++) { - auto Coord = geometry->nodes->GetCoord(iPoint); - for (iDim = 0; iDim < nDim; iDim++) { - if ((Coord[iDim] < MinCoordValues[iDim]) || (Coord[iDim] > MaxCoordValues[iDim])) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } - - /*--- Don't move the volume grid outside the limits based - on the distance to the solid surface ---*/ - - if (config->GetDeform_Limit() < 1E6) { - for (iPoint = 0; iPoint < nPoint; iPoint++) { - if (geometry->nodes->GetWall_Distance(iPoint) >= config->GetDeform_Limit()) { - for (iDim = 0; iDim < nDim; iDim++) { - total_index = iPoint * nDim + iDim; - LinSysRes[total_index] = 0.0; - LinSysSol[total_index] = 0.0; - StiffMatrix.DeleteValsRowi(total_index); - } - } - } - } -} - void CVolumetricMovement::Rigid_Rotation(CGeometry* geometry, CConfig* config, unsigned short iZone, - unsigned long iter) { + unsigned long iter) { /*--- Local variables ---*/ unsigned short iDim, nDim; unsigned long iPoint; @@ -2067,7 +630,7 @@ void CVolumetricMovement::Rigid_Rotation(CGeometry* geometry, CConfig* config, u } void CVolumetricMovement::Rigid_Pitching(CGeometry* geometry, CConfig* config, unsigned short iZone, - unsigned long iter) { + unsigned long iter) { /*--- Local variables ---*/ su2double r[3] = {0.0, 0.0, 0.0}, rotCoord[3] = {0.0, 0.0, 0.0}, *Coord, Center[3] = {0.0, 0.0, 0.0}, Omega[3] = {0.0, 0.0, 0.0}, Ampl[3] = {0.0, 0.0, 0.0}, Phase[3] = {0.0, 0.0, 0.0}; @@ -2213,7 +776,7 @@ void CVolumetricMovement::Rigid_Pitching(CGeometry* geometry, CConfig* config, u } void CVolumetricMovement::Rigid_Plunging(CGeometry* geometry, CConfig* config, unsigned short iZone, - unsigned long iter) { + unsigned long iter) { /*--- Local variables ---*/ su2double deltaX[3], newCoord[3] = {0.0, 0.0, 0.0}, Center[3], *Coord, Omega[3], Ampl[3], Lref; su2double *GridVel, newGridVel[3] = {0.0, 0.0, 0.0}, xDot[3]; @@ -2603,3 +1166,4 @@ void CVolumetricMovement::SetVolume_Rotation(CGeometry* geometry, CConfig* confi /*--- After moving all nodes, update geometry class ---*/ if (UpdateGeo) UpdateDualGrid(geometry, config); } + diff --git a/Common/src/grid_movement/CVolumetricMovementFactory.cpp b/Common/src/grid_movement/CVolumetricMovementFactory.cpp new file mode 100644 index 00000000000..62a346aa8a8 --- /dev/null +++ b/Common/src/grid_movement/CVolumetricMovementFactory.cpp @@ -0,0 +1,50 @@ +/*! + * \file CVolumetricMovementFactory.cpp + * \brief Factory to generate volumetric mover objects. + * \version 8.0.1 "Harrier" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2023, 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/CConfig.hpp" + +#include "../../include/grid_movement/CVolumetricMovementFactory.hpp" +#include "../../include/grid_movement/CRadialBasisFunctionInterpolation.hpp" +#include "../../include/grid_movement/CLinearElasticity.hpp" + + +namespace CVolumetricMovementFactory{ + + CVolumetricMovement* CreateCVolumetricMovement(CGeometry* geometry, CConfig* config){ + const auto type = config->GetDeform_Kind(); + CVolumetricMovement* VolumetricMovement = nullptr; + switch(type){ + case DEFORM_KIND::RBF: + VolumetricMovement = new CRadialBasisFunctionInterpolation(geometry, config); + break; + case DEFORM_KIND::ELASTIC: + VolumetricMovement = new CLinearElasticity(geometry, config); + + } + return VolumetricMovement; + } + + } // namespace CVolumetricMovemementFactory diff --git a/Common/src/grid_movement/meson.build b/Common/src/grid_movement/meson.build index e543d642a94..8b19bed7401 100644 --- a/Common/src/grid_movement/meson.build +++ b/Common/src/grid_movement/meson.build @@ -4,4 +4,8 @@ common_src += files(['CGridMovement.cpp', 'CBezierBlending.cpp', 'CFreeFormDefBox.cpp', 'CVolumetricMovement.cpp', - 'CSurfaceMovement.cpp']) + 'CSurfaceMovement.cpp', + 'CVolumetricMovementFactory.cpp', + 'ClinearElasticity.cpp', + 'CRadialBasisFunctionInterpolation.cpp', + 'CRadialBasisFunctionNode.cpp']) diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 7160cc93e6f..70f6f612693 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -96,6 +96,8 @@ #include "../../../Common/include/parallelization/omp_structure.hpp" +#include "../../../Common/include/grid_movement/CVolumetricMovementFactory.hpp" + #include #ifdef VTUNEPROF @@ -2387,7 +2389,8 @@ void CDriver::PreprocessDynamicMesh(CConfig *config, CGeometry **geometry, CSolv if (!fem_solver && (config->GetGrid_Movement() || (config->GetDirectDiff() == D_DESIGN))) { if (rank == MASTER_NODE) cout << "Setting dynamic mesh structure for zone "<< iZone + 1<<"." << endl; - grid_movement = new CVolumetricMovement(geometry[MESH_0], config); + // grid_movement = new CVolumetricMovement(geometry[MESH_0], config); + grid_movement = CVolumetricMovementFactory::CreateCVolumetricMovement(geometry[MESH_0], config); surface_movement = new CSurfaceMovement(); surface_movement->CopyBoundary(geometry[MESH_0], config); diff --git a/SU2_DEF/src/drivers/CDeformationDriver.cpp b/SU2_DEF/src/drivers/CDeformationDriver.cpp index ed33ef219bc..e620e6ac1f3 100644 --- a/SU2_DEF/src/drivers/CDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDeformationDriver.cpp @@ -32,6 +32,8 @@ #include "../../../SU2_CFD/include/output/CMeshOutput.hpp" #include "../../../SU2_CFD/include/solvers/CMeshSolver.hpp" +#include "../../../Common/include/grid_movement/CVolumetricMovementFactory.hpp" + using namespace std; CDeformationDriver::CDeformationDriver(char* confFile, SU2_Comm MPICommunicator) @@ -315,8 +317,8 @@ void CDeformationDriver::DeformLegacy() { /*--- Definition of the Class for grid movement. ---*/ grid_movement[iZone] = new CVolumetricMovement*[nInst_Zone](); - grid_movement[iZone][INST_0] = - new CVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + grid_movement[iZone][INST_0] = + CVolumetricMovementFactory::CreateCVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); /*--- Save original coordinates to be reused in convexity checking procedure. ---*/ diff --git a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp index 6e07e6b4108..3421bf615a7 100644 --- a/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp +++ b/SU2_DEF/src/drivers/CDiscAdjDeformationDriver.cpp @@ -31,7 +31,7 @@ #include "../../../Common/include/geometry/CPhysicalGeometry.hpp" #include "../../../Common/include/grid_movement/CSurfaceMovement.hpp" -#include "../../../Common/include/grid_movement/CVolumetricMovement.hpp" +#include "../../../Common/include/grid_movement/CVolumetricMovementFactory.hpp" #include "../../../SU2_CFD/include/numerics/CGradSmoothing.hpp" #include "../../../SU2_CFD/include/output/CBaselineOutput.hpp" #include "../../../SU2_CFD/include/solvers/CBaselineSolver.hpp" @@ -285,8 +285,7 @@ void CDiscAdjDeformationDriver::Preprocess() { unsigned short nInst_Zone = nInst[iZone]; grid_movement[iZone] = new CVolumetricMovement*[nInst_Zone](); - grid_movement[iZone][INST_0] = - new CVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); + grid_movement[iZone][INST_0] = CVolumetricMovementFactory::CreateCVolumetricMovement(geometry_container[iZone][INST_0][MESH_0], config_container[iZone]); /*--- Read in sensitivities from file. ---*/ From 595dd7cd7f9b53696beb70f2c184609fde3d172a Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Tue, 12 Mar 2024 22:12:26 +0100 Subject: [PATCH 03/19] changes .gitignore --- .gitignore | 7 +++++++ 1 file changed, 7 insertions(+) diff --git a/.gitignore b/.gitignore index 2177d44e12e..de46aa105d4 100644 --- a/.gitignore +++ b/.gitignore @@ -103,3 +103,10 @@ su2preconfig.timestamp # Clangd server files .cache + + + +ninja-win.zip +ninja.exe +.gitignore +Docs/html From 35f419f59a38c125d35a86df14bce6fa250414e0 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 13 Mar 2024 13:59:27 +0100 Subject: [PATCH 04/19] Add destructors for ELA, RBF --- Common/include/grid_movement/CLinearElasticity.hpp | 5 ++++- .../grid_movement/CRadialBasisFunctionInterpolation.hpp | 9 ++++----- Common/src/grid_movement/CLinearElasticity.cpp | 1 + .../grid_movement/CRadialBasisFunctionInterpolation.cpp | 2 ++ 4 files changed, 11 insertions(+), 6 deletions(-) diff --git a/Common/include/grid_movement/CLinearElasticity.hpp b/Common/include/grid_movement/CLinearElasticity.hpp index 02ad40c8181..b95f3a87797 100644 --- a/Common/include/grid_movement/CLinearElasticity.hpp +++ b/Common/include/grid_movement/CLinearElasticity.hpp @@ -63,7 +63,10 @@ class CLinearElasticity final: public CVolumetricMovement{ */ CLinearElasticity(CGeometry* geometry, CConfig* config); - //TODO add deconstructor + /*! + * \brief Destructor of the class. + */ + ~CLinearElasticity(void) override; /*! * \brief Grid deformation using the spring analogy method. diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index dde59f291dc..63f835b41d3 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -54,17 +54,16 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { su2double radius; /*!< \brief Support radius of compact Radial Basis Function.*/ public: - // TODO make destructor /*! * \brief Constructor of the class. */ CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config); - // /*! - // * \brief Destructor of the class. - // */ - // ~CGridRadialBasisFunction(void) override; + /*! + * \brief Destructor of the class. + */ + ~CRadialBasisFunctionInterpolation(void) override; /*! * \brief Grid deformation using the spring analogy method. diff --git a/Common/src/grid_movement/CLinearElasticity.cpp b/Common/src/grid_movement/CLinearElasticity.cpp index abb355a8c85..1f7b6f99a55 100644 --- a/Common/src/grid_movement/CLinearElasticity.cpp +++ b/Common/src/grid_movement/CLinearElasticity.cpp @@ -47,6 +47,7 @@ CLinearElasticity::CLinearElasticity(CGeometry* geometry, CConfig* config):CVolu } }; +CLinearElasticity::~CLinearElasticity(void) = default; void CLinearElasticity::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative) { diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index b569c7c9d28..acde5bb7044 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -38,6 +38,8 @@ CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* controlNodes = &boundaryNodes; } +CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation(void) = default; + void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative){ /*--- Retrieving number of deformation steps. ---*/ From 45d98551a284da85ba4ba5da6f6e1b92847b4c7c Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 13 Mar 2024 15:57:38 +0100 Subject: [PATCH 05/19] Mods to output for RBF --- Common/src/CConfig.cpp | 14 ++++++- .../CRadialBasisFunctionInterpolation.cpp | 41 ++++++++++++++++++- 2 files changed, 53 insertions(+), 2 deletions(-) diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 5737c4700c6..7e8077f0f38 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6459,7 +6459,19 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { if (val_software == SU2_COMPONENT::SU2_DEF) { cout << endl <<"---------------- Grid deformation parameters ( Zone " << iZone << " ) ----------------" << endl; - cout << "Grid deformation using a linear elasticity method." << endl; + cout << "Grid deformation using a "; + if (Deform_Kind == DEFORM_KIND::RBF){ + cout << "Radial Basis Function interpolation method.\nRadial Basis Function: "; + switch(Kind_RadialBasisFunction){ + case RADIAL_BASIS::WENDLAND_C2: cout << "Wendland C2." << endl; break; + case RADIAL_BASIS::INV_MULTI_QUADRIC: cout << "inversed multi quartic biharmonic spline." << endl; break; + case RADIAL_BASIS::GAUSSIAN: cout << "Guassian." << endl; break; + case RADIAL_BASIS::THIN_PLATE_SPLINE: cout << "thin plate spline." << endl; break; + case RADIAL_BASIS::MULTI_QUADRIC: cout << "multi quartic biharmonic spline." << endl; break; + } + }else{ + cout << "linear elasticity method." << endl; + } if (Hold_GridFixed == YES) cout << "Hold some regions of the mesh fixed (hardcode implementation)." << endl; } diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index acde5bb7044..4a79bf309c2 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -42,21 +42,57 @@ CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation(void) = de void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative){ - /*--- Retrieving number of deformation steps. ---*/ + su2double MinVolume, MaxVolume; + + /*--- Retrieving number of deformation steps and screen output from config ---*/ + auto Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); + auto Screen_Output = config->GetDeform_Output(); + + /*--- Disable the screen output if we're running SU2_CFD ---*/ + + if (config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD && !Derivative) Screen_Output = false; + if (config->GetSmoothGradient()) Screen_Output = true; + /*--- Assigning the node types ---*/ SetControlNodes(geometry, config); SetInternalNodes(geometry); /*--- Looping over the number of deformation iterations ---*/ for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { + + /*--- Compute min volume in the entire mesh. ---*/ + + ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); + if (rank == MASTER_NODE && Screen_Output) + cout << "Min. volume: " << MinVolume << ", max. volume: " << MaxVolume << "." << endl; /*--- Obtaining the interpolation coefficients of the control nodes ---*/ GetInterpolationCoefficients(geometry, config, iNonlinear_Iter); /*--- Updating the coordinates of the grid ---*/ UpdateGridCoord(geometry, config); + + if(UpdateGeo){ + UpdateDualGrid(geometry, config); + } + + /*--- Check for failed deformation (negative volumes). ---*/ + + ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); + + /*--- Calculate amount of nonconvex elements ---*/ + + ComputenNonconvexElements(geometry, Screen_Output); + + if (rank == MASTER_NODE && Screen_Output) { + cout << "Non-linear iter.: " << iNonlinear_Iter + 1 << "/" << Nonlinear_Iter << ". "; + if (nDim == 2) + cout << "Min. area: " << MinVolume << "." << endl; + else + cout << "Min. volume: " << MinVolume << "." << endl; + } } } @@ -190,9 +226,12 @@ void CRadialBasisFunctionInterpolation::SolveRBF_System(){ for(iDim = 0; iDim < nDim; iDim++){ interpMat.MatVecMult(deformationVector.begin()+iDim*controlNodes->size(), coefficients.begin()+iDim*controlNodes->size()); } + + cout << endl; } void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CConfig* config){ + cout << "updating the grid coordinates" << endl; unsigned long iNode, cNode; unsigned short iDim; From 1dae1d310f76c81636ac756a00b258cb32831e84 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Tue, 19 Mar 2024 14:07:05 +0100 Subject: [PATCH 06/19] Additional options data reduction RBF mesh deformation. --- Common/include/CConfig.hpp | 21 +++++++++++++++++++++ Common/src/CConfig.cpp | 6 ++++++ 2 files changed, 27 insertions(+) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 8503759ed42..d91cf6b0d22 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -653,6 +653,9 @@ class CConfig { su2double Deform_Coeff; /*!< \brief Deform coeffienct */ su2double Deform_Limit; /*!< \brief Deform limit */ DEFORM_KIND Deform_Kind; /*!< \brief Type of mesh deformation */ + bool RBF_DataReduction; /*!< \brief Determines use of data reduction methods for RBF mesh deformation. */ + su2double RBF_GreedyTolerance; /*!< \brief Tolerance used in the greedy data reduction for RBF mesh deformation. */ + su2double RBF_GreedyCorrectionFactor; /*!< \brief Correction factor used in the greedy algorithm for RBF mesh deformation. */ unsigned short FFD_Continuity; /*!< \brief Surface continuity at the intersection with the FFD */ unsigned short FFD_CoordSystem; /*!< \brief Define the coordinates system */ su2double Deform_ElasticityMod, /*!< \brief Young's modulus for volume deformation stiffness model */ @@ -4382,6 +4385,24 @@ class CConfig { */ DEFORM_KIND GetDeform_Kind(void) const { return Deform_Kind; } + /*! + * \brief Determines use of data reduction methods for RBF mesh deformation. + * \return TRUE means that data reduction is used. + */ + bool GetRBF_DataReduction(void) const { return RBF_DataReduction; } + + /*! + * \brief Determines use of data reduction methods for RBF mesh deformation. + * \return TRUE means that data reduction is used. + */ + su2double GetRBF_GreedyTolerance(void) const { return RBF_GreedyTolerance; } + + /*! + * \brief Determines use of data reduction methods for RBF mesh deformation. + * \return TRUE means that data reduction is used. + */ + su2double GetRBF_GreedyCorrectionFactor(void) const { return RBF_GreedyCorrectionFactor; } + /*! * \brief Get the kind of SU2 software component. * \return Kind of the SU2 software component. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 7e8077f0f38..ef9a78a71c2 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -2377,6 +2377,12 @@ void CConfig::SetConfig_Options() { addUnsignedLongOption("DEFORM_LINEAR_SOLVER_ITER", Deform_Linear_Solver_Iter, 1000); /* DESCRIPTION: Type of mesh deformation */ addEnumOption("DEFORM_KIND", Deform_Kind, Deform_Kind_Map, DEFORM_KIND::ELASTIC); + /* DESCRIPTION: Use of data reduction methods for RBF interpolated mesh deformation */ + addBoolOption("RBF_DATA_REDUCTION", RBF_DataReduction, true); + /* DESCRIPTION: Tolerance for the data reduction methods used in RBF mesh deformation. */ + addDoubleOption("RBF_GREEDY_TOLERANCE", RBF_GreedyTolerance, 1E-2); + /* DESCRIPTION: Tolerance for the data reduction methods used in RBF mesh deformation. */ + addDoubleOption("RBF_GREEDY_CORRECTION_FACTOR", RBF_GreedyCorrectionFactor, 1E-2); /*!\par CONFIG_CATEGORY: FEM flow solver definition \ingroup Config*/ /*--- Options related to the finite element flow solver---*/ From 048042c7624a390b61f198f7f88d7d6c2d2b249d Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Tue, 19 Mar 2024 16:41:11 +0100 Subject: [PATCH 07/19] New option in config file for internal boundaries. In case of internal boundaries that are allowed to move freely based on the deformation of moving boundaries, these options enable it to do so. --- Common/include/CConfig.hpp | 31 ++++++++++++ Common/src/CConfig.cpp | 49 +++++++++++++++++-- Common/src/geometry/CPhysicalGeometry.cpp | 3 ++ .../CRadialBasisFunctionInterpolation.cpp | 8 ++- 4 files changed, 85 insertions(+), 6 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index d91cf6b0d22..18e90aa8581 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -189,6 +189,7 @@ class CConfig { nMarker_ActDiskBemOutlet_Axis, /*!< \brief Number of actuator disk BEM outlet markers passed to MARKER_ACTDISK_BEM_AXIS. */ nMarker_Deform_Mesh_Sym_Plane, /*!< \brief Number of markers with symmetric deformation */ nMarker_Deform_Mesh, /*!< \brief Number of deformable markers at the boundary. */ + nMarker_Deform_Mesh_Internal, /*!< \brief Number of internal markers allowed to freely deform. */ nMarker_Fluid_Load, /*!< \brief Number of markers in which the flow load is computed/employed. */ nMarker_Fluid_InterfaceBound, /*!< \brief Number of fluid interface markers. */ nMarker_CHTInterface, /*!< \brief Number of conjugate heat transfer interface markers. */ @@ -238,6 +239,7 @@ class CConfig { *Marker_NearFieldBound, /*!< \brief Near Field boundaries markers. */ *Marker_Deform_Mesh, /*!< \brief Deformable markers at the boundary. */ *Marker_Deform_Mesh_Sym_Plane, /*!< \brief Marker with symmetric deformation. */ + *Marker_Deform_Mesh_Internal, /*!< \brief Internal marker allowed to freely deform. */ *Marker_Fluid_Load, /*!< \brief Markers in which the flow load is computed/employed. */ *Marker_Fluid_InterfaceBound, /*!< \brief Fluid interface markers. */ *Marker_CHTInterface, /*!< \brief Conjugate heat transfer interface markers. */ @@ -750,6 +752,7 @@ class CConfig { *Marker_All_Moving, /*!< \brief Global index for moving surfaces using the grid information. */ *Marker_All_Deform_Mesh, /*!< \brief Global index for deformable markers at the boundary. */ *Marker_All_Deform_Mesh_Sym_Plane, /*!< \brief Global index for markers with symmetric deformations. */ + *Marker_All_Deform_Mesh_Internal, /*!< \brief Global index for internal markers with free deformation. */ *Marker_All_Fluid_Load, /*!< \brief Global index for markers in which the flow load is computed/employed. */ *Marker_All_PyCustom, /*!< \brief Global index for Python customizable surfaces using the grid information. */ *Marker_All_Designing, /*!< \brief Global index for moving using the grid information. */ @@ -766,6 +769,7 @@ class CConfig { *Marker_CfgFile_Moving, /*!< \brief Global index for moving surfaces using the config information. */ *Marker_CfgFile_Deform_Mesh, /*!< \brief Global index for deformable markers at the boundary. */ *Marker_CfgFile_Deform_Mesh_Sym_Plane, /*!< \brief Global index for markers with symmetric deformations. */ + *Marker_CfgFile_Deform_Mesh_Internal, /*!< \brief Global index for internal markers with free deformation. */ *Marker_CfgFile_Fluid_Load, /*!< \brief Global index for markers in which the flow load is computed/employed. */ *Marker_CfgFile_PyCustom, /*!< \brief Global index for Python customizable surfaces using the config information. */ *Marker_CfgFile_DV, /*!< \brief Global index for design variable markers using the config information. */ @@ -3491,6 +3495,14 @@ class CConfig { */ void SetMarker_All_Deform_Mesh_Sym_Plane(unsigned short val_marker, unsigned short val_deform) { Marker_All_Deform_Mesh_Sym_Plane[val_marker] = val_deform; } + /*! + * \brief Set if a marker val_marker allows deformation at the boundary. + * \param[in] val_marker - Index of the marker in which we are interested. + * \param[in] val_interface - 0 or 1 depending if the the marker is or not a DEFORM_MESH_SYM_PLANE marker. + */ + void SetMarker_All_Deform_Mesh_Internal(unsigned short val_marker, unsigned short val_deform) { Marker_All_Deform_Mesh_Internal[val_marker] = val_deform; } + + /*! * \brief Set if a in marker val_marker the flow load will be computed/employed. * \param[in] val_marker - Index of the marker in which we are interested. @@ -3641,6 +3653,13 @@ class CConfig { * \return 0 or 1 depending if the marker belongs to the DEFORM_MESH_SYM_PLANE subset. */ unsigned short GetMarker_All_Deform_Mesh_Sym_Plane(unsigned short val_marker) const { return Marker_All_Deform_Mesh_Sym_Plane[val_marker]; } + + /*! + * \brief Get whether marker val_marker is a DEFORM_MESH_SYM_PLANE marker + * \param[in] val_marker - 0 or 1 depending if the the marker belongs to the DEFORM_MESH_SYM_PLANE subset. + * \return 0 or 1 depending if the marker belongs to the DEFORM_MESH_SYM_PLANE subset. + */ + unsigned short GetMarker_All_Deform_Mesh_Internal(unsigned short val_marker) const { return Marker_All_Deform_Mesh_Internal[val_marker]; } /*! * \brief Get whether marker val_marker is a Fluid_Load marker @@ -6387,6 +6406,12 @@ class CConfig { */ unsigned short GetMarker_CfgFile_Deform_Mesh_Sym_Plane(const string& val_marker) const; + /*! + * \brief Get the DEFORM_MESH_INTERNAL information from the config definition for the marker val_marker. + * \return DEFORM_MESH_INTERNAL information of the boundary in the config information for the marker val_marker. + */ + unsigned short GetMarker_CfgFile_Deform_Mesh_Internal(const string& val_marker) const; + /*! * \brief Get the Fluid_Load information from the config definition for the marker val_marker. * \return Fluid_Load information of the boundary in the config information for the marker val_marker. @@ -6742,6 +6767,12 @@ class CConfig { */ unsigned short GetMarker_Deform_Mesh_Sym_Plane(const string& val_marker) const; + /*! + * \brief Get the internal index for a DEFORM_MESH_SYM_PLANE boundary val_marker. + * \return Internal index for a DEFORM_MESH_SYM_PLANE boundary val_marker. + */ + unsigned short GetMarker_Deform_Mesh_Internal(const string& val_marker) const; + /*! * \brief Get a bool for whether the marker is deformed. val_marker. * \param[in] val_marker - Name of the marker to test. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index ef9a78a71c2..0d0fe6e5e71 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -837,6 +837,7 @@ void CConfig::SetPointersNull() { Marker_CfgFile_ZoneInterface = nullptr; Marker_CfgFile_Deform_Mesh = nullptr; Marker_All_Deform_Mesh = nullptr; Marker_CfgFile_Deform_Mesh_Sym_Plane = nullptr; Marker_All_Deform_Mesh_Sym_Plane = nullptr; + Marker_CfgFile_Deform_Mesh_Internal = nullptr; Marker_All_Deform_Mesh_Internal = nullptr; Marker_CfgFile_Fluid_Load = nullptr; Marker_All_Fluid_Load = nullptr; Marker_CfgFile_SobolevBC = nullptr; Marker_All_SobolevBC = nullptr; @@ -863,7 +864,8 @@ void CConfig::SetPointersNull() { Marker_Euler = nullptr; Marker_FarField = nullptr; Marker_Custom = nullptr; Marker_SymWall = nullptr; Marker_PerBound = nullptr; Marker_PerDonor = nullptr; Marker_NearFieldBound = nullptr; Marker_Inlet_Turb = nullptr; - Marker_Deform_Mesh = nullptr; Marker_Deform_Mesh_Sym_Plane= nullptr; Marker_Fluid_Load = nullptr; + Marker_Deform_Mesh = nullptr; Marker_Deform_Mesh_Sym_Plane= nullptr; Marker_Deform_Mesh_Internal= nullptr; + Marker_Fluid_Load = nullptr; Marker_Inlet = nullptr; Marker_Outlet = nullptr; Marker_Inlet_Species = nullptr; Marker_Supersonic_Inlet = nullptr; Marker_Supersonic_Outlet = nullptr; Marker_Smoluchowski_Maxwell= nullptr; Marker_Isothermal = nullptr; Marker_HeatFlux = nullptr; Marker_EngineInflow = nullptr; @@ -1497,6 +1499,8 @@ void CConfig::SetConfig_Options() { addStringListOption("MARKER_DEFORM_MESH", nMarker_Deform_Mesh, Marker_Deform_Mesh); /*!\brief MARKER_DEFORM_MESH_SYM_PLANE\n DESCRIPTION: Symmetry plane for mesh deformation only \ingroup Config*/ addStringListOption("MARKER_DEFORM_MESH_SYM_PLANE", nMarker_Deform_Mesh_Sym_Plane, Marker_Deform_Mesh_Sym_Plane); + /*!\brief MARKER_DEFORM_MESH_INTERNAL\n DESCRIPTION: Internal marker for mesh deformation only \ingroup Config*/ + addStringListOption("MARKER_DEFORM_MESH_INTERNAL", nMarker_Deform_Mesh_Internal, Marker_Deform_Mesh_Internal); /*!\brief MARKER_FLUID_LOAD\n DESCRIPTION: Marker(s) in which the flow load is computed/applied \ingroup Config*/ addStringListOption("MARKER_FLUID_LOAD", nMarker_Fluid_Load, Marker_Fluid_Load); /*!\brief MARKER_FSI_INTERFACE \n DESCRIPTION: ZONE interface boundary marker(s) \ingroup Config*/ @@ -5571,7 +5575,7 @@ void CConfig::SetMarkers(SU2_COMPONENT val_software) { iMarker_Monitoring, iMarker_Designing, iMarker_GeoEval, iMarker_Plotting, iMarker_Analyze, iMarker_DV, iMarker_Moving, iMarker_SobolevBC, iMarker_PyCustom, iMarker_Supersonic_Inlet, iMarker_Supersonic_Outlet, iMarker_Clamped, iMarker_ZoneInterface, iMarker_CHTInterface, iMarker_Load_Dir, iMarker_Disp_Dir, - iMarker_Fluid_Load, iMarker_Deform_Mesh, iMarker_Deform_Mesh_Sym_Plane, + iMarker_Fluid_Load, iMarker_Deform_Mesh, iMarker_Deform_Mesh_Sym_Plane, iMarker_Deform_Mesh_Internal, iMarker_ActDiskInlet, iMarker_ActDiskOutlet, iMarker_Turbomachinery, iMarker_MixingPlaneInterface; @@ -5615,6 +5619,7 @@ void CConfig::SetMarkers(SU2_COMPONENT val_software) { Marker_All_Moving = new unsigned short[nMarker_All] (); // Store whether the boundary should be in motion. Marker_All_Deform_Mesh = new unsigned short[nMarker_All] (); // Store whether the boundary is deformable. Marker_All_Deform_Mesh_Sym_Plane = new unsigned short[nMarker_All] (); //Store wheter the boundary will follow the deformation + Marker_All_Deform_Mesh_Internal = new unsigned short[nMarker_All] (); //Store wheter the boundary will follow the deformation Marker_All_Fluid_Load = new unsigned short[nMarker_All] (); // Store whether the boundary computes/applies fluid loads. Marker_All_PyCustom = new unsigned short[nMarker_All] (); // Store whether the boundary is Python customizable. Marker_All_PerBound = new short[nMarker_All] (); // Store whether the boundary belongs to a periodic boundary. @@ -5641,6 +5646,7 @@ void CConfig::SetMarkers(SU2_COMPONENT val_software) { Marker_CfgFile_Moving = new unsigned short[nMarker_CfgFile] (); Marker_CfgFile_Deform_Mesh = new unsigned short[nMarker_CfgFile] (); Marker_CfgFile_Deform_Mesh_Sym_Plane= new unsigned short[nMarker_CfgFile] (); + Marker_CfgFile_Deform_Mesh_Internal = new unsigned short[nMarker_CfgFile] (); Marker_CfgFile_Fluid_Load = new unsigned short[nMarker_CfgFile] (); Marker_CfgFile_PerBound = new unsigned short[nMarker_CfgFile] (); Marker_CfgFile_Turbomachinery = new unsigned short[nMarker_CfgFile] (); @@ -6055,6 +6061,13 @@ void CConfig::SetMarkers(SU2_COMPONENT val_software) { Marker_CfgFile_Deform_Mesh_Sym_Plane[iMarker_CfgFile] = YES; } + for (iMarker_CfgFile = 0; iMarker_CfgFile < nMarker_CfgFile; iMarker_CfgFile++) { + Marker_CfgFile_Deform_Mesh_Internal[iMarker_CfgFile] = NO; + for (iMarker_Deform_Mesh_Internal = 0; iMarker_Deform_Mesh_Internal < nMarker_Deform_Mesh_Internal; iMarker_Deform_Mesh_Internal++) + if (Marker_CfgFile_TagBound[iMarker_CfgFile] == Marker_Deform_Mesh_Internal[iMarker_Deform_Mesh_Internal]) + Marker_CfgFile_Deform_Mesh_Internal[iMarker_CfgFile] = YES; + } + for (iMarker_CfgFile = 0; iMarker_CfgFile < nMarker_CfgFile; iMarker_CfgFile++) { Marker_CfgFile_Fluid_Load[iMarker_CfgFile] = NO; for (iMarker_Fluid_Load = 0; iMarker_Fluid_Load < nMarker_Fluid_Load; iMarker_Fluid_Load++) @@ -6083,8 +6096,8 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { unsigned short iMarker_Euler, iMarker_Custom, iMarker_FarField, iMarker_SymWall, iMarker_PerBound, iMarker_NearFieldBound, iMarker_Fluid_InterfaceBound, iMarker_Inlet, iMarker_Riemann, - iMarker_Deform_Mesh, iMarker_Deform_Mesh_Sym_Plane, iMarker_Fluid_Load, - iMarker_Smoluchowski_Maxwell, iWall_Catalytic, + iMarker_Deform_Mesh, iMarker_Deform_Mesh_Sym_Plane, iMarker_Deform_Mesh_Internal, + iMarker_Fluid_Load, iMarker_Smoluchowski_Maxwell, iWall_Catalytic, iMarker_Giles, iMarker_Outlet, iMarker_Isothermal, iMarker_HeatFlux, iMarker_HeatTransfer, iMarker_EngineInflow, iMarker_EngineExhaust, iMarker_Displacement, iMarker_Damper, iMarker_Load, iMarker_Internal, iMarker_Monitoring, @@ -7369,6 +7382,15 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { BoundaryTable.PrintFooter(); } + if (nMarker_Deform_Mesh_Internal!= 0) { + BoundaryTable << "Internal freely deformable mesh boundary"; + for (iMarker_Deform_Mesh_Internal = 0; iMarker_Deform_Mesh_Internal < nMarker_Deform_Mesh_Internal; iMarker_Deform_Mesh_Internal++) { + BoundaryTable << Marker_Deform_Mesh_Internal[iMarker_Deform_Mesh_Internal]; + if (iMarker_Deform_Mesh_Internal < nMarker_Deform_Mesh_Internal-1) BoundaryTable << " "; + } + BoundaryTable.PrintFooter(); + } + if (nMarker_Fluid_Load != 0) { BoundaryTable << "Fluid loads boundary"; for (iMarker_Fluid_Load = 0; iMarker_Fluid_Load < nMarker_Fluid_Load; iMarker_Fluid_Load++) { @@ -7923,6 +7945,13 @@ unsigned short CConfig::GetMarker_CfgFile_Deform_Mesh_Sym_Plane(const string& va return Marker_CfgFile_Deform_Mesh_Sym_Plane[iMarker_CfgFile]; } +unsigned short CConfig::GetMarker_CfgFile_Deform_Mesh_Internal(const string& val_marker) const { + unsigned short iMarker_CfgFile; + for (iMarker_CfgFile = 0; iMarker_CfgFile < nMarker_CfgFile; iMarker_CfgFile++) + if (Marker_CfgFile_TagBound[iMarker_CfgFile] == val_marker) break; + return Marker_CfgFile_Deform_Mesh_Internal[iMarker_CfgFile]; +} + unsigned short CConfig::GetMarker_CfgFile_Fluid_Load(const string& val_marker) const { unsigned short iMarker_CfgFile; for (iMarker_CfgFile = 0; iMarker_CfgFile < nMarker_CfgFile; iMarker_CfgFile++) @@ -8067,6 +8096,9 @@ CConfig::~CConfig() { delete[] Marker_CfgFile_Deform_Mesh_Sym_Plane; delete[] Marker_All_Deform_Mesh_Sym_Plane; + delete[] Marker_CfgFile_Deform_Mesh_Internal; + delete[] Marker_All_Deform_Mesh_Internal; + delete[] Marker_CfgFile_Fluid_Load; delete[] Marker_All_Fluid_Load; @@ -8859,6 +8891,15 @@ unsigned short CConfig::GetMarker_Deform_Mesh_Sym_Plane(const string& val_marker return iMarker; } +unsigned short CConfig::GetMarker_Deform_Mesh_Internal(const string& val_marker) const { + unsigned short iMarker; + + /*--- Find the marker for this internal boundary. ---*/ + for (iMarker = 0; iMarker < nMarker_Deform_Mesh_Internal; iMarker++) + if (Marker_Deform_Mesh_Internal[iMarker] == val_marker) break; + return iMarker; +} + unsigned short CConfig::GetMarker_Fluid_Load(const string& val_marker) const { unsigned short iMarker_Fluid_Load; diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 8d245ce1206..c64499b817e 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -3365,6 +3365,7 @@ void CPhysicalGeometry::SetBoundaries(CConfig* config) { config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); config->SetMarker_All_Deform_Mesh(iMarker, config->GetMarker_CfgFile_Deform_Mesh(Marker_Tag)); config->SetMarker_All_Deform_Mesh_Sym_Plane(iMarker, config->GetMarker_CfgFile_Deform_Mesh_Sym_Plane(Marker_Tag)); + config->SetMarker_All_Deform_Mesh_Internal(iMarker, config->GetMarker_CfgFile_Deform_Mesh_Internal(Marker_Tag)); config->SetMarker_All_Fluid_Load(iMarker, config->GetMarker_CfgFile_Fluid_Load(Marker_Tag)); config->SetMarker_All_PyCustom(iMarker, config->GetMarker_CfgFile_PyCustom(Marker_Tag)); config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); @@ -3389,6 +3390,7 @@ void CPhysicalGeometry::SetBoundaries(CConfig* config) { config->SetMarker_All_Moving(iMarker, NO); config->SetMarker_All_Deform_Mesh(iMarker, NO); config->SetMarker_All_Deform_Mesh_Sym_Plane(iMarker, NO); + config->SetMarker_All_Deform_Mesh_Internal(iMarker, NO); config->SetMarker_All_Fluid_Load(iMarker, NO); config->SetMarker_All_PyCustom(iMarker, NO); config->SetMarker_All_PerBound(iMarker, NO); @@ -3758,6 +3760,7 @@ void CPhysicalGeometry::LoadUnpartitionedSurfaceElements(CConfig* config, CMeshR config->SetMarker_All_Moving(iMarker, config->GetMarker_CfgFile_Moving(Marker_Tag)); config->SetMarker_All_Deform_Mesh(iMarker, config->GetMarker_CfgFile_Deform_Mesh(Marker_Tag)); config->SetMarker_All_Deform_Mesh_Sym_Plane(iMarker, config->GetMarker_CfgFile_Deform_Mesh_Sym_Plane(Marker_Tag)); + config->SetMarker_All_Deform_Mesh_Internal(iMarker, config->GetMarker_CfgFile_Deform_Mesh_Internal(Marker_Tag)); config->SetMarker_All_Fluid_Load(iMarker, config->GetMarker_CfgFile_Fluid_Load(Marker_Tag)); config->SetMarker_All_PyCustom(iMarker, config->GetMarker_CfgFile_PyCustom(Marker_Tag)); config->SetMarker_All_PerBound(iMarker, config->GetMarker_CfgFile_PerBound(Marker_Tag)); diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 4a79bf309c2..5370493250b 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -119,7 +119,9 @@ void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CCo /*--- Total number of boundary nodes (including duplicates of shared boundaries) ---*/ unsigned long nBoundNodes = 0; for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ - nBoundNodes += geometry->nVertex[iMarker]; + if(!config->GetMarker_All_Deform_Mesh_Internal(iMarker)){ + nBoundNodes += geometry->nVertex[iMarker]; + } } /*--- Vector with boudary nodes has at most nBoundNodes ---*/ @@ -129,8 +131,10 @@ void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CCo unsigned long count = 0; for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ for(iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ - boundaryNodes[count+iVertex] = new CRadialBasisFunctionNode(geometry, iMarker, iVertex); + if(!config->GetMarker_All_Deform_Mesh_Internal(iMarker)){ + boundaryNodes[count+iVertex] = new CRadialBasisFunctionNode(geometry, iMarker, iVertex); } + } count += geometry->nVertex[iMarker]; } From 6fa701029f7415779cc46c9693ba98c02bfc7c29 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Fri, 3 May 2024 15:58:04 +0200 Subject: [PATCH 08/19] type in meson build file --- Common/src/grid_movement/meson.build | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/src/grid_movement/meson.build b/Common/src/grid_movement/meson.build index 8b19bed7401..9def4449483 100644 --- a/Common/src/grid_movement/meson.build +++ b/Common/src/grid_movement/meson.build @@ -6,6 +6,6 @@ common_src += files(['CGridMovement.cpp', 'CVolumetricMovement.cpp', 'CSurfaceMovement.cpp', 'CVolumetricMovementFactory.cpp', - 'ClinearElasticity.cpp', + 'CLinearElasticity.cpp', 'CRadialBasisFunctionInterpolation.cpp', 'CRadialBasisFunctionNode.cpp']) From af39ccbab91a9967348adcfa1fa37ef42261b40b Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 22 May 2024 14:19:27 +0200 Subject: [PATCH 09/19] [WIP] working version of parallel RBF computation. Requires some clean up work --- .../CRadialBasisFunctionInterpolation.hpp | 11 +- .../CRadialBasisFunctionNode.hpp | 2 +- .../CRadialBasisFunctionInterpolation.cpp | 323 ++++++++++++++---- .../CRadialBasisFunctionNode.cpp | 4 +- externals/codi | 2 +- 5 files changed, 268 insertions(+), 74 deletions(-) diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index 63f835b41d3..cc72eb40f7f 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -40,6 +40,8 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { protected: vector boundaryNodes; /*!< \brief Vector with boundary nodes.*/ + vector boundaryNodes_local; /*!< \brief Vector with boundary nodes.*/ + vector boundNodes, boundNodes_local; vector internalNodes; /*!< \brief Vector with internal nodes.*/ unsigned long nBoundaryNodes, /*!< \brief Number of boundary nodes*/ nInternalNodes; /*!< \brief Number of internal nodes*/ @@ -47,8 +49,11 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { vector* controlNodes; /*!< \brief Vector with control nodes*/ vector deformationVector; /*!< \brief Deformation vector.*/ + vector deformationVector_local; /*!< \brief Deformation vector.*/ + vector coefficients; /*!< \brief Control node interpolation coefficients.*/ CSymmetricMatrix interpMat; /*!< \brief Interpolation matrix.*/ + // su2activematrix interpMat; RADIAL_BASIS kindRBF; /*!< \brief Type of Radial Basis Function.*/ su2double radius; /*!< \brief Support radius of compact Radial Basis Function.*/ @@ -108,7 +113,7 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { * \brief Selecting internal nodes for the volumetric deformation. * \param[in] geometry - Geometrical definition of the problem. */ - void SetInternalNodes(CGeometry* geometry); + void SetInternalNodes(CConfig* config, CGeometry* geometry); /*! * \brief Solving of the Radial Basis Function interpolation system, yielding the interpolation coefficients @@ -140,4 +145,8 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { inline static bool Equal(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ return a->GetIndex() == b->GetIndex(); } + + inline static bool Equal2(unsigned long a, unsigned long b){ + return a == b; + }; }; \ No newline at end of file diff --git a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp index 989a9cd35c6..3f1e64eeaad 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp @@ -47,7 +47,7 @@ class CRadialBasisFunctionNode{ /*! * \brief Constructor of the class. */ - CRadialBasisFunctionNode(CGeometry* geometry, unsigned short marker_val, unsigned long vertex_val); + CRadialBasisFunctionNode(unsigned long idx_val, unsigned short marker_val, unsigned long vertex_val); /*! * \brief Returns global index. diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 5370493250b..7455d6741f8 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -34,8 +34,9 @@ CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* /*--- Retrieve type of RBF and if applicable its support radius ---*/ kindRBF = config->GetKindRadialBasisFunction(); radius = config->GetRadialBasisFunctionParameter(); - + controlNodes = &boundaryNodes; + } CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation(void) = default; @@ -57,7 +58,7 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr /*--- Assigning the node types ---*/ SetControlNodes(geometry, config); - SetInternalNodes(geometry); + SetInternalNodes(config, geometry); //TODO change order /*--- Looping over the number of deformation iterations ---*/ for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { @@ -73,6 +74,16 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr /*--- Updating the coordinates of the grid ---*/ UpdateGridCoord(geometry, config); + + + // #ifdef HAVE_MPI + + // SU2_MPI::Barrier(SU2_MPI::GetComm()); + // SU2_MPI::Abort(SU2_MPI::GetComm(), 0); + // #else + // std::exit(0); + // #endif + if(UpdateGeo){ UpdateDualGrid(geometry, config); @@ -102,40 +113,35 @@ void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* if(iNonlinear_Iter == 0){ SetDeformationVector(geometry, config); } - + /*--- Computing the interpolation matrix with RBF evaluations based on Euclidean distance ---*/ SetInterpolationMatrix(geometry, config); - + /*--- Solving the RBF system to get the interpolation coefficients ---*/ - SolveRBF_System(); + SolveRBF_System(); + } void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CConfig* config){ + + vector vertices; + vector markers; unsigned short iMarker; unsigned short iVertex; - /*--- Total number of boundary nodes (including duplicates of shared boundaries) ---*/ - unsigned long nBoundNodes = 0; - for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ - if(!config->GetMarker_All_Deform_Mesh_Internal(iMarker)){ - nBoundNodes += geometry->nVertex[iMarker]; - } - } - - /*--- Vector with boudary nodes has at most nBoundNodes ---*/ - boundaryNodes.resize(nBoundNodes); - /*--- Storing of the global, marker and vertex indices ---*/ - unsigned long count = 0; + unsigned long node; for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ - for(iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ - if(!config->GetMarker_All_Deform_Mesh_Internal(iMarker)){ - boundaryNodes[count+iVertex] = new CRadialBasisFunctionNode(geometry, iMarker, iVertex); + if(!config->GetMarker_All_Deform_Mesh_Internal(iMarker) && !config->GetMarker_All_SendRecv(iMarker)){ + for(iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ + node = geometry->vertex[iMarker][iVertex]->GetNode(); + if(geometry->nodes->GetDomain(node)){ + boundaryNodes.push_back(new CRadialBasisFunctionNode(node, iMarker, iVertex)); + } } } - count += geometry->nVertex[iMarker]; } /*--- Sorting of the boundary nodes based on global index ---*/ @@ -143,42 +149,89 @@ void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CCo /*--- Obtaining unique set of boundary nodes ---*/ boundaryNodes.resize(std::distance(boundaryNodes.begin(), unique(boundaryNodes.begin(), boundaryNodes.end(), Equal))); - + /*--- Updating the number of boundary nodes ---*/ nBoundaryNodes = boundaryNodes.size(); - + + // for(auto x : boundaryNodes){cout << rank << " " << x->GetIndex() << " " << geometry->nodes->GetGlobalIndex(x->GetIndex()) << endl;} } void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geometry, CConfig* config){ + auto rank = SU2_MPI::GetRank(); unsigned long iNode, jNode; - /*--- Initialization of the interpolation matrix ---*/ - interpMat.Initialize(controlNodes->size()); + unsigned long interpMatSize; + #ifdef HAVE_MPI - /*--- Construction of the interpolation matrix. - Since this matrix is symmetric only upper halve has to be considered ---*/ + //obtaining the global size of the coordinates + unsigned long size; + SU2_MPI::Reduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, SU2_MPI::GetComm()); + if(rank != MASTER_NODE){ + size = 0; + } + su2double coords[size*nDim]; - /*--- Looping over the target nodes ---*/ - for(iNode = 0; iNode < controlNodes->size(); iNode++ ){ - /*--- Looping over the control nodes ---*/ - for (jNode = iNode; jNode < controlNodes->size(); jNode++){ + su2double coords_local[nBoundaryNodes*nDim]; + + for(iNode = 0; iNode < controlNodes->size(); iNode++){ + // auto coord = geometry->vertex[(*controlNodes)[iNode]->GetMarker()][(*controlNodes)[iNode]->GetVertex()]->GetCoord(); + auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); + coords_local[iNode*nDim] = coord[0]; + coords_local[iNode*nDim+1] = coord[1]; + } - /*--- Distance between nodes ---*/ - auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); - - /*--- Evaluation of RBF ---*/ - interpMat(iNode, jNode) = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + + SU2_MPI::Gather(&coords_local, nBoundaryNodes*nDim, MPI_DOUBLE, &coords, nBoundaryNodes*nDim, MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); + + interpMatSize = size; + #else + interpMatSize = nBoundaryNodes; + #endif + + if(rank == MASTER_NODE){ + /*--- Initialization of the interpolation matrix ---*/ + interpMat.Initialize(interpMatSize); + + /*--- Construction of the interpolation matrix. + Since this matrix is symmetric only upper halve has to be considered ---*/ + + + /*--- Looping over the target nodes ---*/ + for(iNode = 0; iNode < interpMatSize; iNode++ ){ + + /*--- Looping over the control nodes ---*/ + for (jNode = iNode; jNode < interpMatSize; jNode++){ + + /*--- Distance between nodes ---*/ + // auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); + #ifdef HAVE_MPI + su2double dist(0); + + for (unsigned short i = 0; i < nDim; i++) dist += pow(coords[iNode*nDim+i] - coords[jNode*nDim+i], 2); + dist = sqrt(dist); + + #else + // auto dist = GeometryToolbox::Distance(nDim, geometry->vertex[(*controlNodes)[iNode]->GetMarker()][(*controlNodes)[iNode]->GetVertex()]->GetCoord(), geometry->vertex[(*controlNodes)[jNode]->GetMarker()][(*controlNodes)[jNode]->GetVertex()]->GetCoord()); + auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); + #endif + /*--- Evaluation of RBF ---*/ + interpMat(iNode, jNode) = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + } } - } - /*--- Obtaining lower halve using symmetry ---*/ - const bool kernelIsSPD = (kindRBF == RADIAL_BASIS::WENDLAND_C2) || (kindRBF == RADIAL_BASIS::GAUSSIAN) || - (kindRBF == RADIAL_BASIS::INV_MULTI_QUADRIC); - interpMat.Invert(kernelIsSPD); + // /*--- Obtaining lower halve using symmetry ---*/ + const bool kernelIsSPD = (kindRBF == RADIAL_BASIS::WENDLAND_C2) || (kindRBF == RADIAL_BASIS::GAUSSIAN) || + (kindRBF == RADIAL_BASIS::INV_MULTI_QUADRIC); + // SU2_MPI::Send(interpMat.data(), interpMat.size(), MPI_DOUBLE, rank, MASTER_NODE, SU2_MPI::GetComm()); + + interpMat.Invert(kernelIsSPD); + } } void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry, CConfig* config){ + auto rank = SU2_MPI::GetRank(); + /* --- Initialization of the deformation vector ---*/ deformationVector.resize(controlNodes->size()*nDim, 0.0); @@ -189,56 +242,169 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry /*--- Setting nonzero displacements of the moving markers ---*/ for(auto i = 0; i < controlNodes->size(); i++){ + if(config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())){ for(auto iDim = 0; iDim < nDim; iDim++){ deformationVector[i+iDim*controlNodes->size()] = SU2_TYPE::GetValue(geometry->vertex[(*controlNodes)[i]->GetMarker()][(*controlNodes)[i]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); } } } + + + + + #ifdef HAVE_MPI + deformationVector_local = deformationVector; + + unsigned long deformationVectorSize, deformationVectorSize_local = deformationVector.size(); + + SU2_MPI::Allreduce(&deformationVectorSize_local, &deformationVectorSize, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + + if(rank==MASTER_NODE){ + auto size = SU2_MPI::GetSize(); + deformationVector.resize(deformationVectorSize); + unsigned long defVecSizes[size]; + + SU2_MPI::Gather(&deformationVectorSize_local, 1, MPI_UNSIGNED_LONG, defVecSizes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + + int counts_recv[size]; + int displacements[size]; + + for(int i = 0; i < size; i++){ + counts_recv[i] = 1; + if(i == 0){ + displacements[i] = 0; + }else{ + displacements[i] = displacements[i-1] + defVecSizes[i-1]; + } + } + + }else{ + SU2_MPI::Gather(&deformationVectorSize_local, 1, MPI_UNSIGNED_LONG, NULL, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + } + + SU2_MPI::Gather(deformationVector_local.data(), deformationVectorSize_local, MPI_DOUBLE, deformationVector.data(), deformationVectorSize_local, MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); + + + if(rank == MASTER_NODE){ + // setting correct order of the deformation vector + for(unsigned short processor = 0; processor < SU2_MPI::GetSize(); processor++){ + //todo include loop for dimensions + for(unsigned short iDim = 0; iDim < nDim-1; iDim++){ + unsigned long start_idx = nBoundaryNodes*(processor+1); + + deformationVector.insert(deformationVector.end(), deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+nBoundaryNodes); + deformationVector.erase(deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+nBoundaryNodes); + + } + } + } + #endif } -void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry){ +void CRadialBasisFunctionInterpolation::SetInternalNodes(CConfig* config, CGeometry* geometry){ /*--- resizing the internal nodes vector ---*/ - nInternalNodes = geometry->GetnPoint() - nBoundaryNodes; + nInternalNodes = geometry->GetnPoint() - nBoundaryNodes; // vector has max size of nPoints internalNodes.resize(nInternalNodes); + /*--- Looping over all nodes and check if present in boundary nodes vector ---*/ unsigned long idx_cnt = 0, idx_control = 0; - for(unsigned long iNode = 0; iNode < geometry->GetnPoint(); iNode++){ - - /*--- If iNode is equal to boundaryNodes[idx_control] - then this node is a boundary node and idx_control can be updated ---*/ - if(idx_control < nBoundaryNodes && iNode == boundaryNodes[idx_control]->GetIndex()){idx_control++;} - - /*--- If not equal then the node is an internal node ---*/ - else{ - internalNodes[idx_cnt] = iNode; - idx_cnt++; + for(unsigned long iNode = 0; iNode < geometry->GetnPoint(); iNode++){ + if(!geometry->nodes->GetBoundary(iNode) && geometry->nodes->GetDomain(iNode)){ + internalNodes[idx_cnt++] = iNode; } } + + #ifdef HAVE_MPI + for(unsigned short iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++){ //TODO cleanup + if(config->GetMarker_All_SendRecv(iMarker)){ // if send receive marker + for(unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ + if(geometry->nodes->GetDomain(geometry->vertex[iMarker][iVertex]->GetNode())){ + auto node = geometry->vertex[iMarker][iVertex]->GetNode(); + if(find_if(boundaryNodes.begin(), boundaryNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == node;}) == boundaryNodes.end()){ + internalNodes[idx_cnt++] = node; + } + + + }else{ + auto node = geometry->vertex[iMarker][iVertex]->GetNode(); + internalNodes[idx_cnt++] = node; + } + } + } + } + #endif + nInternalNodes = idx_cnt; + internalNodes.resize(nInternalNodes); } void CRadialBasisFunctionInterpolation::SolveRBF_System(){ - + auto rank = SU2_MPI::GetRank(); + #ifdef HAVE_MPI + unsigned long size; + SU2_MPI::Allreduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + #else + size = controlNodes->size(); + #endif /*--- resizing the interpolation coefficient vector ---*/ - coefficients.resize(nDim*controlNodes->size()); + coefficients.resize(nDim*size); - /*--- Looping through the dimensions in order to find the interpolation coefficients for each direction ---*/ - unsigned short iDim; - for(iDim = 0; iDim < nDim; iDim++){ - interpMat.MatVecMult(deformationVector.begin()+iDim*controlNodes->size(), coefficients.begin()+iDim*controlNodes->size()); + if(rank == MASTER_NODE){ + /*--- Looping through the dimensions in order to find the interpolation coefficients for each direction ---*/ + unsigned short iDim; + for(iDim = 0; iDim < nDim; iDim++){ + interpMat.MatVecMult(deformationVector.begin()+iDim*size, coefficients.begin()+iDim*size); + } + + cout << endl; } - cout << endl; + #ifdef HAVE_MPI + SU2_MPI::Bcast(coefficients.data(), coefficients.size(), MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); + #endif } void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CConfig* config){ - cout << "updating the grid coordinates" << endl; + if(rank == MASTER_NODE){ + cout << "updating the grid coordinates" << endl; + } unsigned long iNode, cNode; unsigned short iDim; + + unsigned long size; + #ifdef HAVE_MPI + + //obtaining the global size of the coordinates + SU2_MPI::Allreduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + + su2double coords[size*nDim]; + + su2double coords_local[nBoundaryNodes*nDim]; + + for(iNode = 0; iNode < controlNodes->size(); iNode++){ + // auto coord = geometry->vertex[(*controlNodes)[iNode]->GetMarker()][(*controlNodes)[iNode]->GetVertex()]->GetCoord(); + auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); + coords_local[iNode*nDim] = coord[0]; + coords_local[iNode*nDim+1] = coord[1]; + } + + + SU2_MPI::Allgather(&coords_local, nBoundaryNodes*nDim, MPI_DOUBLE, &coords, nBoundaryNodes*nDim, MPI_DOUBLE, SU2_MPI::GetComm()); + + #else + size = nBoundaryNodes; + #endif + + // if(rank == MASTER_NODE){ + // for(auto x = 0; x < geometry->GetnPoint(); x++){ + // cout << x << " " << geometry->nodes->GetCoord(x)[0] << " " << geometry->nodes->GetCoord(x)[1] << endl; + // } + // } + /*--- Vector for storing the coordinate variation ---*/ su2double var_coord[nDim]; @@ -246,17 +412,25 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo for(iNode = 0; iNode < nInternalNodes; iNode++){ /*--- Loop for contribution of each control node ---*/ - for(cNode = 0; cNode < controlNodes->size(); cNode++){ - + for(cNode = 0; cNode < size; cNode++){ + /*--- Determine distance between considered internal and control node ---*/ - auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(internalNodes[iNode])); - + su2double dist; + + #ifdef HAVE_MPI + dist = 0; + for (unsigned short i = 0; i < nDim; i++) dist += pow(coords[cNode*nDim+i] - geometry->nodes->GetCoord(internalNodes[iNode])[i], 2); + dist = sqrt(dist); + #else + dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(internalNodes[iNode])); + #endif + /*--- Evaluate RBF based on distance ---*/ auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); - + /*--- Add contribution to total coordinate variation ---*/ for( iDim = 0; iDim < nDim; iDim++){ - var_coord[iDim] += rbf*coefficients[cNode + iDim*controlNodes->size()]; + var_coord[iDim] += rbf*coefficients[cNode + iDim*size]; } } @@ -266,14 +440,25 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo var_coord[iDim] = 0; } } + + /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ - for(cNode = 0; cNode < controlNodes->size(); cNode++){ + for(cNode = 0; cNode < nBoundaryNodes; cNode++){ if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ for(iDim = 0; iDim < nDim; iDim++){ - geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*controlNodes->size()]); + #ifdef HAVE_MPI + geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector_local[cNode + iDim*nBoundaryNodes]); + #else + geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nBoundaryNodes]); + #endif } } } + // if(rank == MASTER_NODE){ + // for(auto x = 0; x < geometry->GetnPoint(); x++){ + // cout << x << " " << geometry->nodes->GetCoord(x)[0] << " " << geometry->nodes->GetCoord(x)[1] << endl; + // } + // } } diff --git a/Common/src/grid_movement/CRadialBasisFunctionNode.cpp b/Common/src/grid_movement/CRadialBasisFunctionNode.cpp index ac3addf5303..f3bdea69046 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionNode.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionNode.cpp @@ -27,8 +27,8 @@ #include "../../include/grid_movement/CRadialBasisFunctionNode.hpp" -CRadialBasisFunctionNode::CRadialBasisFunctionNode(CGeometry* geometry, unsigned short marker_val, unsigned long vertex_val){ - idx = geometry->vertex[marker_val][vertex_val]->GetNode(); +CRadialBasisFunctionNode::CRadialBasisFunctionNode(unsigned long idx_val, unsigned short marker_val, unsigned long vertex_val){ + idx = idx_val; marker_idx = marker_val; vertex_idx = vertex_val; }; \ No newline at end of file diff --git a/externals/codi b/externals/codi index c6b039e5c9e..9ca6c382806 160000 --- a/externals/codi +++ b/externals/codi @@ -1 +1 @@ -Subproject commit c6b039e5c9edb7675f90ffc725f9dd8e66571264 +Subproject commit 9ca6c38280610b3ea5337ca3e5b5085ee1c66b59 From ca6ce89bf815db61aa18272b17b5b2fde3af4ae4 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Thu, 30 May 2024 10:51:11 +0200 Subject: [PATCH 10/19] [WIP] Updated parallel computation RBF interpolation --- .../CRadialBasisFunctionInterpolation.hpp | 2 +- .../CRadialBasisFunctionInterpolation.cpp | 320 +++++++++++------- 2 files changed, 203 insertions(+), 119 deletions(-) diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index cc72eb40f7f..56ee1272194 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -113,7 +113,7 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { * \brief Selecting internal nodes for the volumetric deformation. * \param[in] geometry - Geometrical definition of the problem. */ - void SetInternalNodes(CConfig* config, CGeometry* geometry); + void SetInternalNodes(CGeometry* geometry, CConfig* config); /*! * \brief Solving of the Radial Basis Function interpolation system, yielding the interpolation coefficients diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 7455d6741f8..a5e4ea536a0 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -56,9 +56,11 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr if (config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD && !Derivative) Screen_Output = false; if (config->GetSmoothGradient()) Screen_Output = true; + /*--- Assigning the node types ---*/ SetControlNodes(geometry, config); - SetInternalNodes(config, geometry); //TODO change order + SetInternalNodes(geometry, config); + /*--- Looping over the number of deformation iterations ---*/ for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { @@ -74,16 +76,7 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr /*--- Updating the coordinates of the grid ---*/ UpdateGridCoord(geometry, config); - - // #ifdef HAVE_MPI - - // SU2_MPI::Barrier(SU2_MPI::GetComm()); - // SU2_MPI::Abort(SU2_MPI::GetComm(), 0); - // #else - // std::exit(0); - // #endif - if(UpdateGeo){ UpdateDualGrid(geometry, config); @@ -125,26 +118,32 @@ void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CConfig* config){ - vector vertices; - vector markers; unsigned short iMarker; - unsigned short iVertex; + unsigned long iVertex, iNode; + /*--- Storing of the node, marker and vertex information ---*/ - /*--- Storing of the global, marker and vertex indices ---*/ - unsigned long node; - for(iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++){ - if(!config->GetMarker_All_Deform_Mesh_Internal(iMarker) && !config->GetMarker_All_SendRecv(iMarker)){ - for(iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ - node = geometry->vertex[iMarker][iVertex]->GetNode(); - if(geometry->nodes->GetDomain(node)){ - boundaryNodes.push_back(new CRadialBasisFunctionNode(node, iMarker, iVertex)); + /*--- Looping over the markers ---*/ + for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + + /*--- Checking if not internal or send/receive marker ---*/ + if (!config->GetMarker_All_Deform_Mesh_Internal(iMarker) && !config->GetMarker_All_SendRecv(iMarker)) { + + /*--- Looping over the vertices of marker ---*/ + for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Node in consideration ---*/ + iNode = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- Check whether node is part of the subdomain and not shared with a receiving marker (for parallel computation)*/ + if (geometry->nodes->GetDomain(iNode)) { + boundaryNodes.push_back(new CRadialBasisFunctionNode(iNode, iMarker, iVertex)); } } } } - /*--- Sorting of the boundary nodes based on global index ---*/ + /*--- Sorting of the boundary nodes based on their index ---*/ sort(boundaryNodes.begin(), boundaryNodes.end(), Compare); /*--- Obtaining unique set of boundary nodes ---*/ @@ -152,39 +151,75 @@ void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CCo /*--- Updating the number of boundary nodes ---*/ nBoundaryNodes = boundaryNodes.size(); - - // for(auto x : boundaryNodes){cout << rank << " " << x->GetIndex() << " " << geometry->nodes->GetGlobalIndex(x->GetIndex()) << endl;} } void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geometry, CConfig* config){ - auto rank = SU2_MPI::GetRank(); + unsigned long iNode, jNode; - unsigned long interpMatSize; + + /*--- In case of parallel computation, the interpolation coefficients are computed on the master node. + In order to do so the coordinates of all control nodes are collected on the master node ---*/ + #ifdef HAVE_MPI - //obtaining the global size of the coordinates - unsigned long size; + /*--- Obtaining global number of control nodes on master node ---*/ + unsigned long size; //TODO use different variable here, as size is used as nr of processes outside of this scope SU2_MPI::Reduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, SU2_MPI::GetComm()); - if(rank != MASTER_NODE){ - size = 0; + + /*--- For other processes size is equal to local number of control nodes ---*/ + if( rank != MASTER_NODE ){ + size = nBoundaryNodes; } + + /*--- array containing coordinates of control nodes. Global control nodes for master node, + local control nodes for other processes. ---*/ su2double coords[size*nDim]; - su2double coords_local[nBoundaryNodes*nDim]; - - for(iNode = 0; iNode < controlNodes->size(); iNode++){ - // auto coord = geometry->vertex[(*controlNodes)[iNode]->GetMarker()][(*controlNodes)[iNode]->GetVertex()]->GetCoord(); - auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); - coords_local[iNode*nDim] = coord[0]; - coords_local[iNode*nDim+1] = coord[1]; + /*--- Storing coordinates in array ---*/ + for (iNode = 0; iNode < controlNodes->size(); iNode++) { + + auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); + + for (unsigned short iDim = 0; iDim < nDim; iDim++) { + coords[iNode*nDim+iDim] = coord[iDim]; + } } + /*--- Array containing the sizes of the local coordinates. ---*/ + unsigned long localSizes[SU2_MPI::GetSize()]; + + /*--- local size of the coordinates ---*/ + auto local_size = nBoundaryNodes*nDim; + + if( rank == MASTER_NODE ){ + + /*--- gathering the local sizes ---*/ + SU2_MPI::Gather(&local_size, 1, MPI_UNSIGNED_LONG, localSizes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + + /*--- receiving local coordinates from other processes ---*/ + unsigned long start_idx = 0; + for(auto iProc = 0; iProc < SU2_MPI::GetSize(); iProc++){ + + if(iProc != MASTER_NODE){ + SU2_MPI::Recv(&coords[0] + start_idx, localSizes[iProc], MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); // TODO can status ignore be used? + } + start_idx += localSizes[iProc]; + } + + }else{ - SU2_MPI::Gather(&coords_local, nBoundaryNodes*nDim, MPI_DOUBLE, &coords, nBoundaryNodes*nDim, MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); + /*--- gathering local coordinate size ---*/ + SU2_MPI::Gather(&local_size, 1, MPI_UNSIGNED_LONG, NULL, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + /*--- sending local coordinates to the master node ---*/ + SU2_MPI::Send(coords, local_size, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); + } + /*--- setting size of the interpolation matrix ---*/ interpMatSize = size; + #else + /*--- setting size of the interpolation matrix ---*/ interpMatSize = nBoundaryNodes; #endif @@ -203,7 +238,6 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet for (jNode = iNode; jNode < interpMatSize; jNode++){ /*--- Distance between nodes ---*/ - // auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); #ifdef HAVE_MPI su2double dist(0); @@ -211,7 +245,6 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet dist = sqrt(dist); #else - // auto dist = GeometryToolbox::Distance(nDim, geometry->vertex[(*controlNodes)[iNode]->GetMarker()][(*controlNodes)[iNode]->GetVertex()]->GetCoord(), geometry->vertex[(*controlNodes)[jNode]->GetMarker()][(*controlNodes)[jNode]->GetVertex()]->GetCoord()); auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); #endif /*--- Evaluation of RBF ---*/ @@ -230,7 +263,6 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet } void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry, CConfig* config){ - auto rank = SU2_MPI::GetRank(); /* --- Initialization of the deformation vector ---*/ deformationVector.resize(controlNodes->size()*nDim, 0.0); @@ -241,103 +273,146 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); /*--- Setting nonzero displacements of the moving markers ---*/ - for(auto i = 0; i < controlNodes->size(); i++){ + for (auto i = 0; i < controlNodes->size(); i++) { - if(config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())){ - for(auto iDim = 0; iDim < nDim; iDim++){ + if (config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())) { + + for (auto iDim = 0; iDim < nDim; iDim++) { deformationVector[i+iDim*controlNodes->size()] = SU2_TYPE::GetValue(geometry->vertex[(*controlNodes)[i]->GetMarker()][(*controlNodes)[i]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); } } - } + } + - #ifdef HAVE_MPI + + /*--- define local deformation vector ---*/ deformationVector_local = deformationVector; + /*--- sizes for the global and local deformation vectors ---*/ unsigned long deformationVectorSize, deformationVectorSize_local = deformationVector.size(); - SU2_MPI::Allreduce(&deformationVectorSize_local, &deformationVectorSize, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); - + /*--- Obtaining global deformation vector size on master node by summing the local sizes ---*/ + SU2_MPI::Reduce(&deformationVectorSize_local, &deformationVectorSize, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, SU2_MPI::GetComm()); + + /*--- Array containing local deformation vector sizes ---*/ + unsigned long defVecSizes[size]; + + /*--- Gathering all deformation vectors on the master node ---*/ if(rank==MASTER_NODE){ - auto size = SU2_MPI::GetSize(); + + /*--- resizing the global deformation vector ---*/ deformationVector.resize(deformationVectorSize); - unsigned long defVecSizes[size]; + /*--- Gathering the local deformation vector sizes in array defVecSizes ---*/ SU2_MPI::Gather(&deformationVectorSize_local, 1, MPI_UNSIGNED_LONG, defVecSizes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); - - int counts_recv[size]; - int displacements[size]; - - for(int i = 0; i < size; i++){ - counts_recv[i] = 1; - if(i == 0){ - displacements[i] = 0; - }else{ - displacements[i] = displacements[i-1] + defVecSizes[i-1]; + + + /*--- Receiving the local deformation vector from other processes ---*/ + unsigned long start_idx = 0; + for (auto iProc = 0; iProc < size; iProc++) { + if (iProc != MASTER_NODE) { + SU2_MPI::Recv(&deformationVector[0] + start_idx, defVecSizes[iProc], MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); // TODO can status ignore be used? } - } - + start_idx += defVecSizes[iProc]; + } + }else{ + + /*--- Gathering the local deformation vector sizes in array defVecSizes ---*/ SU2_MPI::Gather(&deformationVectorSize_local, 1, MPI_UNSIGNED_LONG, NULL, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + + /*--- Sending the local deformation vector to the master node ---*/ + SU2_MPI::Send(deformationVector_local.data(), deformationVectorSize_local, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); + } - - SU2_MPI::Gather(deformationVector_local.data(), deformationVectorSize_local, MPI_DOUBLE, deformationVector.data(), deformationVectorSize_local, MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); - + /*--- The global deformation vector is now ordered as d_1, d_2, ..., d_n, where n is the number of processes. + Here the deformation vector is reordered to obtain an order x_1, ..., x_n, y_1, ..., y_n, z_1, ..., z_n, + where x_n is the deformation in x of deformation vector n */ if(rank == MASTER_NODE){ - // setting correct order of the deformation vector - for(unsigned short processor = 0; processor < SU2_MPI::GetSize(); processor++){ - //todo include loop for dimensions - for(unsigned short iDim = 0; iDim < nDim-1; iDim++){ - unsigned long start_idx = nBoundaryNodes*(processor+1); + + + for (unsigned short iDim = nDim-1; iDim > 0; iDim--) { - deformationVector.insert(deformationVector.end(), deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+nBoundaryNodes); - deformationVector.erase(deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+nBoundaryNodes); + unsigned long start_idx = 0; + for (unsigned short processor = 0; processor < SU2_MPI::GetSize(); processor++) { + + if ( processor == 0){ + start_idx += defVecSizes[processor]/nDim; + } + else{ + start_idx += (defVecSizes[processor-1]/nDim*(iDim-1) + defVecSizes[processor]/nDim); + } + + /*--- inserting part of vector at end of deformationVector ---*/ + deformationVector.insert(deformationVector.end(), deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+defVecSizes[processor]/nDim); + + /*--- erasing moved part of the vector ---*/ + deformationVector.erase(deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+defVecSizes[processor]/nDim); } } } - #endif + + #endif } -void CRadialBasisFunctionInterpolation::SetInternalNodes(CConfig* config, CGeometry* geometry){ +void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CConfig* config ){ + + unsigned long node; /*--- resizing the internal nodes vector ---*/ - nInternalNodes = geometry->GetnPoint() - nBoundaryNodes; // vector has max size of nPoints + nInternalNodes = geometry->GetnPoint();// - nBoundaryNodes; // vector has max size of nPoints internalNodes.resize(nInternalNodes); - /*--- Looping over all nodes and check if present in boundary nodes vector ---*/ + /*--- Looping over all nodes and check if part of domain and not on boundary ---*/ unsigned long idx_cnt = 0, idx_control = 0; - for(unsigned long iNode = 0; iNode < geometry->GetnPoint(); iNode++){ - if(!geometry->nodes->GetBoundary(iNode) && geometry->nodes->GetDomain(iNode)){ + for (unsigned long iNode = 0; iNode < geometry->GetnPoint(); iNode++) { + if (!geometry->nodes->GetBoundary(iNode)) { internalNodes[idx_cnt++] = iNode; } } + + #ifdef HAVE_MPI - for(unsigned short iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++){ //TODO cleanup - if(config->GetMarker_All_SendRecv(iMarker)){ // if send receive marker - for(unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++){ - if(geometry->nodes->GetDomain(geometry->vertex[iMarker][iVertex]->GetNode())){ - auto node = geometry->vertex[iMarker][iVertex]->GetNode(); - if(find_if(boundaryNodes.begin(), boundaryNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == node;}) == boundaryNodes.end()){ - internalNodes[idx_cnt++] = node; - } - - - }else{ - auto node = geometry->vertex[iMarker][iVertex]->GetNode(); + /*--- Looping over the markers ---*/ + for (unsigned short iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + + /*--- If send or receive marker ---*/ + if (config->GetMarker_All_SendRecv(iMarker)) { + + /*--- Loop over marker vertices ---*/ + for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Local node index ---*/ + node = geometry->vertex[iMarker][iVertex]->GetNode(); + + // /*--- if not among the boundary nodes ---*/ + if (find_if (boundaryNodes.begin(), boundaryNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == node;}) == boundaryNodes.end()) { internalNodes[idx_cnt++] = node; - } + } } } } + + /*--- sorting of the local indices ---*/ + sort(internalNodes.begin(), internalNodes.begin() + idx_cnt); + + /*--- Obtaining unique set of internal nodes ---*/ + internalNodes.resize(std::distance(internalNodes.begin(), unique(internalNodes.begin(), internalNodes.begin() + idx_cnt))); + + /*--- Updating the number of internal nodes ---*/ + nInternalNodes = internalNodes.size(); + + #else + nInternalNodes = idx_cnt; + internalNodes.resize(nInternalNodes); #endif - nInternalNodes = idx_cnt; - internalNodes.resize(nInternalNodes); } @@ -357,9 +432,7 @@ void CRadialBasisFunctionInterpolation::SolveRBF_System(){ unsigned short iDim; for(iDim = 0; iDim < nDim; iDim++){ interpMat.MatVecMult(deformationVector.begin()+iDim*size, coefficients.begin()+iDim*size); - } - - cout << endl; + } } #ifdef HAVE_MPI @@ -375,36 +448,55 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo unsigned short iDim; - unsigned long size; + unsigned long size; //TODO change variable name, overwrites variable size (nr of parallel processes) #ifdef HAVE_MPI - //obtaining the global size of the coordinates + /*--- Obtaining global nr of control nodes on all processes. ---*/ SU2_MPI::Allreduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + /*--- array containing the global control node coordinates. ---*/ su2double coords[size*nDim]; - su2double coords_local[nBoundaryNodes*nDim]; + /*--- local size control node coordinates. ---*/ + int local_size = nBoundaryNodes*nDim; + + /*--- array containing the local control node coordinates. ---*/ + su2double coords_local[local_size]; + /*--- storing local control node coordinates ---*/ for(iNode = 0; iNode < controlNodes->size(); iNode++){ - // auto coord = geometry->vertex[(*controlNodes)[iNode]->GetMarker()][(*controlNodes)[iNode]->GetVertex()]->GetCoord(); auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); - coords_local[iNode*nDim] = coord[0]; - coords_local[iNode*nDim+1] = coord[1]; + for ( unsigned short iDim = 0 ; iDim < nDim; iDim++ ){ + coords_local[ iNode * nDim + iDim ] = coord[iDim]; + } } + /*--- array containing size of local control node coordinates. ---*/ + int sizes[SU2_MPI::GetSize()]; - SU2_MPI::Allgather(&coords_local, nBoundaryNodes*nDim, MPI_DOUBLE, &coords, nBoundaryNodes*nDim, MPI_DOUBLE, SU2_MPI::GetComm()); + /*--- gathering local control node coordinate sizes on all processes. ---*/ + SU2_MPI::Allgather(&local_size, 1, MPI_INT, sizes, 1, MPI_INT, SU2_MPI::GetComm()); + + + /*--- array containing the starting indices for the allgatherv operation*/ + int disps[SU2_MPI::GetSize()]; + + for(auto x = 0; x < SU2_MPI::GetSize(); x++){ + if(x == 0){ + disps[x] = 0; + }else{ + disps[x] = disps[x-1]+sizes[x-1]; + } + } + + + /*--- making global control node coordinates available on all processes ---*/ + SU2_MPI::Allgatherv(&coords_local, local_size, MPI_DOUBLE, &coords, sizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); #else size = nBoundaryNodes; #endif - // if(rank == MASTER_NODE){ - // for(auto x = 0; x < geometry->GetnPoint(); x++){ - // cout << x << " " << geometry->nodes->GetCoord(x)[0] << " " << geometry->nodes->GetCoord(x)[1] << endl; - // } - // } - /*--- Vector for storing the coordinate variation ---*/ su2double var_coord[nDim]; @@ -440,25 +532,17 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo var_coord[iDim] = 0; } } - - /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ for(cNode = 0; cNode < nBoundaryNodes; cNode++){ if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ for(iDim = 0; iDim < nDim; iDim++){ #ifdef HAVE_MPI - geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector_local[cNode + iDim*nBoundaryNodes]); + geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector_local[cNode + iDim*nBoundaryNodes]); #else geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nBoundaryNodes]); #endif } } } - - // if(rank == MASTER_NODE){ - // for(auto x = 0; x < geometry->GetnPoint(); x++){ - // cout << x << " " << geometry->nodes->GetCoord(x)[0] << " " << geometry->nodes->GetCoord(x)[1] << endl; - // } - // } } From d0e78c7be6afd001ed9451cf39dc59a23cb2089a Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Tue, 4 Jun 2024 23:23:28 +0200 Subject: [PATCH 11/19] Improvement parallel computations, start of including data reduction --- .../CRadialBasisFunctionInterpolation.hpp | 29 +- .../CRadialBasisFunctionInterpolation.cpp | 362 ++++++++++-------- 2 files changed, 233 insertions(+), 158 deletions(-) diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index 56ee1272194..1dc84e3bf1c 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -40,8 +40,6 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { protected: vector boundaryNodes; /*!< \brief Vector with boundary nodes.*/ - vector boundaryNodes_local; /*!< \brief Vector with boundary nodes.*/ - vector boundNodes, boundNodes_local; vector internalNodes; /*!< \brief Vector with internal nodes.*/ unsigned long nBoundaryNodes, /*!< \brief Number of boundary nodes*/ nInternalNodes; /*!< \brief Number of internal nodes*/ @@ -49,7 +47,6 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { vector* controlNodes; /*!< \brief Vector with control nodes*/ vector deformationVector; /*!< \brief Deformation vector.*/ - vector deformationVector_local; /*!< \brief Deformation vector.*/ vector coefficients; /*!< \brief Control node interpolation coefficients.*/ CSymmetricMatrix interpMat; /*!< \brief Interpolation matrix.*/ @@ -57,6 +54,26 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { RADIAL_BASIS kindRBF; /*!< \brief Type of Radial Basis Function.*/ su2double radius; /*!< \brief Support radius of compact Radial Basis Function.*/ + + + /*--- data reduction parameters ---*/ + vector greedyNodes; /*!< \brief Vector with selected control nodes in greedy algorithm. */ + bool dataReduction; /*!< \brief Determines whether data reduction is used. */ + unsigned long MaxErrorNode; + su2double MaxError; + + + unsigned long Global_nControlNodes{0}; + /*--- mpi related*/ + + unsigned long Local_nControlNodes; + vector Local_nControlNodesVec; + + vector LocalCoords; + vector GlobalCoords; + + + public: @@ -149,4 +166,10 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { inline static bool Equal2(unsigned long a, unsigned long b){ return a == b; }; + + + /*--- Data reduction functions ---*/ + void GreedyIteration(CGeometry* geometry, CConfig* config); + + void GetInitMaxErrorNode(CGeometry* geometry, CConfig* config); }; \ No newline at end of file diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index a5e4ea536a0..d583cd906c4 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -35,14 +35,23 @@ CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* kindRBF = config->GetKindRadialBasisFunction(); radius = config->GetRadialBasisFunctionParameter(); - controlNodes = &boundaryNodes; + // controlNodes = &boundaryNodes;//TODO start here, for data reduction the greedy nodes should be selected as control nodes and nr of control nodes should be specified. + dataReduction = config->GetRBF_DataReduction(); + + if(dataReduction){ + controlNodes = &greedyNodes; + }else{ + controlNodes = &boundaryNodes; + } } CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation(void) = default; void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative){ + + su2double MinVolume, MaxVolume; /*--- Retrieving number of deformation steps and screen output from config ---*/ @@ -56,11 +65,26 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr if (config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD && !Derivative) Screen_Output = false; if (config->GetSmoothGradient()) Screen_Output = true; + + su2double StartTime = SU2_MPI::Wtime(); /*--- Assigning the node types ---*/ SetControlNodes(geometry, config); - SetInternalNodes(geometry, config); + su2double StopTime = SU2_MPI::Wtime(); + auto UsedTimeCompute = StopTime - StartTime; + + if(rank==MASTER_NODE){ + cout << "Setting control nodes time: " << UsedTimeCompute << " seconds" << endl; + } + StartTime = SU2_MPI::Wtime(); + SetInternalNodes(geometry, config); + StopTime = SU2_MPI::Wtime(); + UsedTimeCompute = StopTime - StartTime; + + if(rank==MASTER_NODE){ + cout << "Setting internal nodes time: " << UsedTimeCompute << " seconds" << endl; + } /*--- Looping over the number of deformation iterations ---*/ for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { @@ -74,9 +98,16 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr /*--- Obtaining the interpolation coefficients of the control nodes ---*/ GetInterpolationCoefficients(geometry, config, iNonlinear_Iter); + + StartTime = SU2_MPI::Wtime(); /*--- Updating the coordinates of the grid ---*/ UpdateGridCoord(geometry, config); - + StopTime = SU2_MPI::Wtime(); + UsedTimeCompute = StopTime - StartTime; + + if(rank==MASTER_NODE){ + cout << "Updating grid coords time: " << UsedTimeCompute << " seconds" << endl; + } if(UpdateGeo){ UpdateDualGrid(geometry, config); @@ -101,17 +132,57 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr } void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* geometry, CConfig* config, unsigned long iNonlinear_Iter){ + + + if(dataReduction){ + + - /*--- Deformation vector only has to be set once ---*/ - if(iNonlinear_Iter == 0){ - SetDeformationVector(geometry, config); + GreedyIteration(geometry, config); + }else{ + + + #ifdef HAVE_MPI + Local_nControlNodes = controlNodes->size(); + + Local_nControlNodesVec.resize(size); + /*--- gathering local control node coordinate sizes on all processes. ---*/ + SU2_MPI::Allgather(&Local_nControlNodes, 1, MPI_UNSIGNED_LONG, Local_nControlNodesVec.data(), 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); + + + Global_nControlNodes = 0; + for( auto& n : Local_nControlNodesVec) Global_nControlNodes += n; + + #endif + + + /*--- Deformation vector only has to be set once ---*/ + su2double StartTime = SU2_MPI::Wtime(); + if(iNonlinear_Iter == 0){ + SetDeformationVector(geometry, config); + } + + su2double StopTime = SU2_MPI::Wtime(); + auto UsedTimeCompute = StopTime - StartTime; + + if(rank==MASTER_NODE){ + cout << "Setting deformation vector time: " << UsedTimeCompute << " seconds" << endl; + } + + + /*--- Computing the interpolation matrix with RBF evaluations based on Euclidean distance ---*/ + SetInterpolationMatrix(geometry, config); + + /*--- Solving the RBF system to get the interpolation coefficients ---*/ + StartTime = SU2_MPI::Wtime(); + SolveRBF_System(); + StopTime = SU2_MPI::Wtime(); + UsedTimeCompute = StopTime - StartTime; + + if(rank==MASTER_NODE){ + cout << "Obtaining interpolation coefficients time: " << UsedTimeCompute << " seconds" << endl; + } } - - /*--- Computing the interpolation matrix with RBF evaluations based on Euclidean distance ---*/ - SetInterpolationMatrix(geometry, config); - - /*--- Solving the RBF system to get the interpolation coefficients ---*/ - SolveRBF_System(); } @@ -154,7 +225,7 @@ void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CCo } void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geometry, CConfig* config){ - + su2double StartTime = SU2_MPI::Wtime(); unsigned long iNode, jNode; unsigned long interpMatSize; @@ -163,85 +234,63 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet #ifdef HAVE_MPI - /*--- Obtaining global number of control nodes on master node ---*/ - unsigned long size; //TODO use different variable here, as size is used as nr of processes outside of this scope - SU2_MPI::Reduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, SU2_MPI::GetComm()); - - /*--- For other processes size is equal to local number of control nodes ---*/ - if( rank != MASTER_NODE ){ - size = nBoundaryNodes; - } + /*--- array containing the global control node coordinates. ---*/ + GlobalCoords.resize(Global_nControlNodes*nDim); - /*--- array containing coordinates of control nodes. Global control nodes for master node, - local control nodes for other processes. ---*/ - su2double coords[size*nDim]; - - /*--- Storing coordinates in array ---*/ - for (iNode = 0; iNode < controlNodes->size(); iNode++) { - - auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); - - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - coords[iNode*nDim+iDim] = coord[iDim]; + /*--- array containing the local control node coordinates. ---*/ + LocalCoords.resize(Local_nControlNodes*nDim); + + /*--- storing local control node coordinates ---*/ + for(iNode = 0; iNode < controlNodes->size(); iNode++){ + auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); + for ( unsigned short iDim = 0 ; iDim < nDim; iDim++ ){ + LocalCoords[ iNode * nDim + iDim ] = coord[iDim]; } } - /*--- Array containing the sizes of the local coordinates. ---*/ - unsigned long localSizes[SU2_MPI::GetSize()]; - - /*--- local size of the coordinates ---*/ - auto local_size = nBoundaryNodes*nDim; - - if( rank == MASTER_NODE ){ - - /*--- gathering the local sizes ---*/ - SU2_MPI::Gather(&local_size, 1, MPI_UNSIGNED_LONG, localSizes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + /*--- array containing size of local control node coordinates. ---*/ + int LocalCoordsSizes[SU2_MPI::GetSize()]; - /*--- receiving local coordinates from other processes ---*/ - unsigned long start_idx = 0; - for(auto iProc = 0; iProc < SU2_MPI::GetSize(); iProc++){ + int localCoordsSize = LocalCoords.size(); + /*--- gathering local control node coordinate sizes on all processes. ---*/ + SU2_MPI::Allgather(&localCoordsSize, 1, MPI_INT, LocalCoordsSizes, 1, MPI_INT, SU2_MPI::GetComm()); + + + /*--- array containing the starting indices for the allgatherv operation*/ + int disps[SU2_MPI::GetSize()]; - if(iProc != MASTER_NODE){ - SU2_MPI::Recv(&coords[0] + start_idx, localSizes[iProc], MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); // TODO can status ignore be used? - } - start_idx += localSizes[iProc]; + for(auto x = 0; x < SU2_MPI::GetSize(); x++){ + if(x == 0){ + disps[x] = 0; + }else{ + disps[x] = disps[x-1]+LocalCoordsSizes[x-1]; } - - }else{ - - /*--- gathering local coordinate size ---*/ - SU2_MPI::Gather(&local_size, 1, MPI_UNSIGNED_LONG, NULL, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); - - /*--- sending local coordinates to the master node ---*/ - SU2_MPI::Send(coords, local_size, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); } - /*--- setting size of the interpolation matrix ---*/ - interpMatSize = size; + + /*--- making global control node coordinates available on all processes ---*/ + SU2_MPI::Allgatherv(LocalCoords.data(), localCoordsSize, MPI_DOUBLE, GlobalCoords.data(), LocalCoordsSizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); //TODO local coords can be deleted after this operation - #else - /*--- setting size of the interpolation matrix ---*/ - interpMatSize = nBoundaryNodes; #endif if(rank == MASTER_NODE){ /*--- Initialization of the interpolation matrix ---*/ - interpMat.Initialize(interpMatSize); + interpMat.Initialize(Global_nControlNodes); /*--- Construction of the interpolation matrix. Since this matrix is symmetric only upper halve has to be considered ---*/ /*--- Looping over the target nodes ---*/ - for(iNode = 0; iNode < interpMatSize; iNode++ ){ + for(iNode = 0; iNode < Global_nControlNodes; iNode++ ){ /*--- Looping over the control nodes ---*/ - for (jNode = iNode; jNode < interpMatSize; jNode++){ + for (jNode = iNode; jNode < Global_nControlNodes; jNode++){ /*--- Distance between nodes ---*/ #ifdef HAVE_MPI su2double dist(0); - for (unsigned short i = 0; i < nDim; i++) dist += pow(coords[iNode*nDim+i] - coords[jNode*nDim+i], 2); + for (unsigned short i = 0; i < nDim; i++) dist += pow(GlobalCoords[iNode*nDim+i] - GlobalCoords[jNode*nDim+i], 2); dist = sqrt(dist); #else @@ -256,9 +305,23 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet const bool kernelIsSPD = (kindRBF == RADIAL_BASIS::WENDLAND_C2) || (kindRBF == RADIAL_BASIS::GAUSSIAN) || (kindRBF == RADIAL_BASIS::INV_MULTI_QUADRIC); + + su2double StopTime = SU2_MPI::Wtime(); + auto UsedTimeCompute = StopTime - StartTime; + + + cout << "setting interp matrix time: " << UsedTimeCompute << " seconds" << endl; // SU2_MPI::Send(interpMat.data(), interpMat.size(), MPI_DOUBLE, rank, MASTER_NODE, SU2_MPI::GetComm()); + StartTime = SU2_MPI::Wtime(); + interpMat.Invert(kernelIsSPD); + StopTime = SU2_MPI::Wtime(); + UsedTimeCompute = StopTime - StartTime; + + + cout << "Inverting matrix time: " << UsedTimeCompute << " seconds" << endl; + } } @@ -275,8 +338,7 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry /*--- Setting nonzero displacements of the moving markers ---*/ for (auto i = 0; i < controlNodes->size(); i++) { - if (config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())) { - + if (config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())) { for (auto iDim = 0; iDim < nDim; iDim++) { deformationVector[i+iDim*controlNodes->size()] = SU2_TYPE::GetValue(geometry->vertex[(*controlNodes)[i]->GetMarker()][(*controlNodes)[i]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); } @@ -284,48 +346,27 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry } - - #ifdef HAVE_MPI - /*--- define local deformation vector ---*/ - deformationVector_local = deformationVector; - - /*--- sizes for the global and local deformation vectors ---*/ - unsigned long deformationVectorSize, deformationVectorSize_local = deformationVector.size(); - - /*--- Obtaining global deformation vector size on master node by summing the local sizes ---*/ - SU2_MPI::Reduce(&deformationVectorSize_local, &deformationVectorSize, 1, MPI_UNSIGNED_LONG, MPI_SUM, MASTER_NODE, SU2_MPI::GetComm()); - - /*--- Array containing local deformation vector sizes ---*/ - unsigned long defVecSizes[size]; - /*--- Gathering all deformation vectors on the master node ---*/ if(rank==MASTER_NODE){ /*--- resizing the global deformation vector ---*/ - deformationVector.resize(deformationVectorSize); - - /*--- Gathering the local deformation vector sizes in array defVecSizes ---*/ - SU2_MPI::Gather(&deformationVectorSize_local, 1, MPI_UNSIGNED_LONG, defVecSizes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); - + deformationVector.resize(Global_nControlNodes*nDim); /*--- Receiving the local deformation vector from other processes ---*/ unsigned long start_idx = 0; for (auto iProc = 0; iProc < size; iProc++) { if (iProc != MASTER_NODE) { - SU2_MPI::Recv(&deformationVector[0] + start_idx, defVecSizes[iProc], MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); // TODO can status ignore be used? + SU2_MPI::Recv(&deformationVector[0] + start_idx, Local_nControlNodesVec[iProc]*nDim, MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); // TODO can status ignore be used? } - start_idx += defVecSizes[iProc]; + start_idx += Local_nControlNodesVec[iProc]*nDim; } }else{ - /*--- Gathering the local deformation vector sizes in array defVecSizes ---*/ - SU2_MPI::Gather(&deformationVectorSize_local, 1, MPI_UNSIGNED_LONG, NULL, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); - /*--- Sending the local deformation vector to the master node ---*/ - SU2_MPI::Send(deformationVector_local.data(), deformationVectorSize_local, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); + SU2_MPI::Send(deformationVector.data(), Local_nControlNodes*nDim, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); } @@ -342,17 +383,17 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry for (unsigned short processor = 0; processor < SU2_MPI::GetSize(); processor++) { if ( processor == 0){ - start_idx += defVecSizes[processor]/nDim; + start_idx += Local_nControlNodesVec[processor]; } else{ - start_idx += (defVecSizes[processor-1]/nDim*(iDim-1) + defVecSizes[processor]/nDim); + start_idx += (Local_nControlNodesVec[processor-1]*(iDim-1) + Local_nControlNodesVec[processor]); } /*--- inserting part of vector at end of deformationVector ---*/ - deformationVector.insert(deformationVector.end(), deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+defVecSizes[processor]/nDim); + deformationVector.insert(deformationVector.end(), deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+Local_nControlNodesVec[processor]); /*--- erasing moved part of the vector ---*/ - deformationVector.erase(deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+defVecSizes[processor]/nDim); + deformationVector.erase(deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+Local_nControlNodesVec[processor]); } } } @@ -418,9 +459,12 @@ void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CC void CRadialBasisFunctionInterpolation::SolveRBF_System(){ auto rank = SU2_MPI::GetRank(); + + unsigned long nControlNodes_local = controlNodes->size(); + #ifdef HAVE_MPI unsigned long size; - SU2_MPI::Allreduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&nControlNodes_local, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); #else size = controlNodes->size(); #endif @@ -447,56 +491,6 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo unsigned long iNode, cNode; unsigned short iDim; - - unsigned long size; //TODO change variable name, overwrites variable size (nr of parallel processes) - #ifdef HAVE_MPI - - /*--- Obtaining global nr of control nodes on all processes. ---*/ - SU2_MPI::Allreduce(&nBoundaryNodes, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); - - /*--- array containing the global control node coordinates. ---*/ - su2double coords[size*nDim]; - - /*--- local size control node coordinates. ---*/ - int local_size = nBoundaryNodes*nDim; - - /*--- array containing the local control node coordinates. ---*/ - su2double coords_local[local_size]; - - /*--- storing local control node coordinates ---*/ - for(iNode = 0; iNode < controlNodes->size(); iNode++){ - auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); - for ( unsigned short iDim = 0 ; iDim < nDim; iDim++ ){ - coords_local[ iNode * nDim + iDim ] = coord[iDim]; - } - } - - /*--- array containing size of local control node coordinates. ---*/ - int sizes[SU2_MPI::GetSize()]; - - /*--- gathering local control node coordinate sizes on all processes. ---*/ - SU2_MPI::Allgather(&local_size, 1, MPI_INT, sizes, 1, MPI_INT, SU2_MPI::GetComm()); - - - /*--- array containing the starting indices for the allgatherv operation*/ - int disps[SU2_MPI::GetSize()]; - - for(auto x = 0; x < SU2_MPI::GetSize(); x++){ - if(x == 0){ - disps[x] = 0; - }else{ - disps[x] = disps[x-1]+sizes[x-1]; - } - } - - - - /*--- making global control node coordinates available on all processes ---*/ - SU2_MPI::Allgatherv(&coords_local, local_size, MPI_DOUBLE, &coords, sizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); - #else - size = nBoundaryNodes; - #endif - /*--- Vector for storing the coordinate variation ---*/ su2double var_coord[nDim]; @@ -504,14 +498,14 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo for(iNode = 0; iNode < nInternalNodes; iNode++){ /*--- Loop for contribution of each control node ---*/ - for(cNode = 0; cNode < size; cNode++){ + for(cNode = 0; cNode < Global_nControlNodes; cNode++){ /*--- Determine distance between considered internal and control node ---*/ su2double dist; #ifdef HAVE_MPI dist = 0; - for (unsigned short i = 0; i < nDim; i++) dist += pow(coords[cNode*nDim+i] - geometry->nodes->GetCoord(internalNodes[iNode])[i], 2); + for ( iDim = 0; iDim < nDim; iDim++) dist += pow(GlobalCoords[cNode * nDim + iDim] - geometry->nodes->GetCoord(internalNodes[iNode])[iDim], 2); dist = sqrt(dist); #else dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(internalNodes[iNode])); @@ -522,7 +516,7 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo /*--- Add contribution to total coordinate variation ---*/ for( iDim = 0; iDim < nDim; iDim++){ - var_coord[iDim] += rbf*coefficients[cNode + iDim*size]; + var_coord[iDim] += rbf*coefficients[cNode + iDim*Global_nControlNodes]; } } @@ -534,15 +528,73 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo } /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ - for(cNode = 0; cNode < nBoundaryNodes; cNode++){ + + unsigned long nControlNodes = deformationVector.size()/nDim; // size on master_node is different in case of mpi + for(cNode = 0; cNode < Local_nControlNodes; cNode++){ if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ for(iDim = 0; iDim < nDim; iDim++){ - #ifdef HAVE_MPI - geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector_local[cNode + iDim*nBoundaryNodes]); + #ifdef HAVE_MPI //TODO these are now the same statements + geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nControlNodes]); #else - geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nBoundaryNodes]); + geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nControlNodes]); #endif } } } } + +void CRadialBasisFunctionInterpolation::GreedyIteration(CGeometry* geometry, CConfig* config) { + if (rank == MASTER_NODE) { + cout << "Starting greedy iteration..." << endl; + } + + GetInitMaxErrorNode(geometry, config); + + unsigned short greedyIter = 0; + + // Gathering the init greedy nodes + unsigned long MaxErrorNodes[size]; + SU2_MPI::Gather(&MaxErrorNode, 1, MPI_UNSIGNED_LONG, MaxErrorNodes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); + + + //gathering the coordinates of the selected greedy nodes. This array should be available on the masternode throughout the greedy iteration. + + vector selectedCoords(nDim); // for now a single node is selected; can be an array? + auto coord = geometry->nodes->GetCoord(boundaryNodes[MaxErrorNode]->GetIndex()); + + for(auto iDim = 0; iDim < nDim; iDim++){ + selectedCoords[iDim] = coord[iDim]; + } + vector greedyCoords; + if(rank==MASTER_NODE){ + greedyCoords.resize(nDim*size); + } + SU2_MPI::Gather(selectedCoords.data(), nDim, MPI_DOUBLE, greedyCoords.data(), nDim, MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); + //TODO what if a different number of greedy nodes are selected? + + if (rank == MASTER_NODE){ + for(auto x : greedyCoords){cout << x << endl;} + } + + + SU2_MPI::Barrier(SU2_MPI::GetComm()); + SU2_MPI::Abort(SU2_MPI::GetComm(), 0); +} + +void CRadialBasisFunctionInterpolation::GetInitMaxErrorNode(CGeometry* geometry, CConfig* config){ + unsigned short iNode; + + su2double maxDeformation = 0.0; + su2double normSquaredDeformation; + su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); + + for(iNode = 0; iNode < nBoundaryNodes; iNode++){ + normSquaredDeformation = GeometryToolbox::SquaredNorm(nDim, geometry->vertex[boundaryNodes[iNode]->GetMarker()][boundaryNodes[iNode]->GetVertex()]->GetVarCoord()); + if(normSquaredDeformation > maxDeformation){ + maxDeformation = normSquaredDeformation; + MaxErrorNode = iNode; + } + } + MaxError = sqrt(maxDeformation) / ((su2double)config->GetGridDef_Nonlinear_Iter()); + // cout << "rank: " << rank << " Max error node: " << MaxErrorNode << endl; +} From 2bc182154ecfb69129c07702cfda6e54dfedb09a Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 5 Jun 2024 09:26:41 +0200 Subject: [PATCH 12/19] Seperate function for MPI specific operations --- .../CRadialBasisFunctionInterpolation.hpp | 4 +- .../CRadialBasisFunctionInterpolation.cpp | 100 +++++++++--------- 2 files changed, 55 insertions(+), 49 deletions(-) diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index 1dc84e3bf1c..40900aa4aad 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -69,7 +69,7 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { unsigned long Local_nControlNodes; vector Local_nControlNodesVec; - vector LocalCoords; + // vector LocalCoords; vector GlobalCoords; @@ -172,4 +172,6 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { void GreedyIteration(CGeometry* geometry, CConfig* config); void GetInitMaxErrorNode(CGeometry* geometry, CConfig* config); + + void MPI_Operations(CGeometry* geometry); }; \ No newline at end of file diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index d583cd906c4..5edd013099d 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -143,16 +143,7 @@ void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* #ifdef HAVE_MPI - Local_nControlNodes = controlNodes->size(); - - Local_nControlNodesVec.resize(size); - /*--- gathering local control node coordinate sizes on all processes. ---*/ - SU2_MPI::Allgather(&Local_nControlNodes, 1, MPI_UNSIGNED_LONG, Local_nControlNodesVec.data(), 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); - - - Global_nControlNodes = 0; - for( auto& n : Local_nControlNodesVec) Global_nControlNodes += n; - + MPI_Operations(geometry); #endif @@ -232,45 +223,7 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet /*--- In case of parallel computation, the interpolation coefficients are computed on the master node. In order to do so the coordinates of all control nodes are collected on the master node ---*/ - #ifdef HAVE_MPI - - /*--- array containing the global control node coordinates. ---*/ - GlobalCoords.resize(Global_nControlNodes*nDim); - - /*--- array containing the local control node coordinates. ---*/ - LocalCoords.resize(Local_nControlNodes*nDim); - - /*--- storing local control node coordinates ---*/ - for(iNode = 0; iNode < controlNodes->size(); iNode++){ - auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); - for ( unsigned short iDim = 0 ; iDim < nDim; iDim++ ){ - LocalCoords[ iNode * nDim + iDim ] = coord[iDim]; - } - } - - /*--- array containing size of local control node coordinates. ---*/ - int LocalCoordsSizes[SU2_MPI::GetSize()]; - - int localCoordsSize = LocalCoords.size(); - /*--- gathering local control node coordinate sizes on all processes. ---*/ - SU2_MPI::Allgather(&localCoordsSize, 1, MPI_INT, LocalCoordsSizes, 1, MPI_INT, SU2_MPI::GetComm()); - - - /*--- array containing the starting indices for the allgatherv operation*/ - int disps[SU2_MPI::GetSize()]; - - for(auto x = 0; x < SU2_MPI::GetSize(); x++){ - if(x == 0){ - disps[x] = 0; - }else{ - disps[x] = disps[x-1]+LocalCoordsSizes[x-1]; - } - } - - /*--- making global control node coordinates available on all processes ---*/ - SU2_MPI::Allgatherv(LocalCoords.data(), localCoordsSize, MPI_DOUBLE, GlobalCoords.data(), LocalCoordsSizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); //TODO local coords can be deleted after this operation - #endif if(rank == MASTER_NODE){ /*--- Initialization of the interpolation matrix ---*/ @@ -598,3 +551,54 @@ void CRadialBasisFunctionInterpolation::GetInitMaxErrorNode(CGeometry* geometry, MaxError = sqrt(maxDeformation) / ((su2double)config->GetGridDef_Nonlinear_Iter()); // cout << "rank: " << rank << " Max error node: " << MaxErrorNode << endl; } + + +void CRadialBasisFunctionInterpolation::MPI_Operations(CGeometry* geometry){ + Local_nControlNodes = controlNodes->size(); + + Local_nControlNodesVec.resize(size); + + /*--- gathering local control node coordinate sizes on all processes. ---*/ + SU2_MPI::Allgather(&Local_nControlNodes, 1, MPI_UNSIGNED_LONG, Local_nControlNodesVec.data(), 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); + + + Global_nControlNodes = 0; + for( auto& n : Local_nControlNodesVec) Global_nControlNodes += n; + + /*--- array containing the global control node coordinates. ---*/ + GlobalCoords.resize(Global_nControlNodes*nDim); + + /*--- array containing the local control node coordinates. ---*/ + vector LocalCoords(nDim*Local_nControlNodes); + + + /*--- storing local control node coordinates ---*/ + for(unsigned long iNode = 0; iNode < controlNodes->size(); iNode++){ + auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); + for ( unsigned short iDim = 0 ; iDim < nDim; iDim++ ){ + LocalCoords[ iNode * nDim + iDim ] = coord[iDim]; + } + } + + /*--- array containing size of local control node coordinates. ---*/ + int LocalCoordsSizes[SU2_MPI::GetSize()]; + + int localCoordsSize = LocalCoords.size(); + /*--- gathering local control node coordinate sizes on all processes. ---*/ + SU2_MPI::Allgather(&localCoordsSize, 1, MPI_INT, LocalCoordsSizes, 1, MPI_INT, SU2_MPI::GetComm()); + + + /*--- array containing the starting indices for the allgatherv operation*/ + int disps[SU2_MPI::GetSize()]; + + for(auto x = 0; x < SU2_MPI::GetSize(); x++){ + if(x == 0){ + disps[x] = 0; + }else{ + disps[x] = disps[x-1]+LocalCoordsSizes[x-1]; + } + } + + /*--- making global control node coordinates available on all processes ---*/ + SU2_MPI::Allgatherv(LocalCoords.data(), localCoordsSize, MPI_DOUBLE, GlobalCoords.data(), LocalCoordsSizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); //TODO local coords can be deleted after this operation +}; \ No newline at end of file From 6344d27bd6d5ece4ac1df51e0bd4846ac7178445 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 5 Jun 2024 09:52:01 +0200 Subject: [PATCH 13/19] Small fixes for sequential computation --- .../grid_movement/CRadialBasisFunctionInterpolation.cpp | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 5edd013099d..02c4c4a1f07 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -136,12 +136,10 @@ void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* if(dataReduction){ - - GreedyIteration(geometry, config); }else{ - - + //TODO find more elegant way to assign this variable + Global_nControlNodes = controlNodes->size(); #ifdef HAVE_MPI MPI_Operations(geometry); #endif @@ -483,7 +481,7 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ unsigned long nControlNodes = deformationVector.size()/nDim; // size on master_node is different in case of mpi - for(cNode = 0; cNode < Local_nControlNodes; cNode++){ + for(cNode = 0; cNode < nControlNodes; cNode++){ if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ for(iDim = 0; iDim < nDim; iDim++){ #ifdef HAVE_MPI //TODO these are now the same statements From 636b61106bb6504acf5a3bbebb2c94cf00e11c1e Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 5 Jun 2024 22:04:24 +0200 Subject: [PATCH 14/19] working version parallel computation with greedy algorithm as data reduction --- .../CRadialBasisFunctionInterpolation.hpp | 10 +- .../CRadialBasisFunctionNode.hpp | 10 +- .../CRadialBasisFunctionInterpolation.cpp | 218 +++++++++++++++--- 3 files changed, 202 insertions(+), 36 deletions(-) diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index 40900aa4aad..fefaf53b1a4 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -61,7 +61,8 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { bool dataReduction; /*!< \brief Determines whether data reduction is used. */ unsigned long MaxErrorNode; su2double MaxError; - + su2double GreedyTolerance; + su2double GreedyCorrectionFactor; unsigned long Global_nControlNodes{0}; /*--- mpi related*/ @@ -71,6 +72,7 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { // vector LocalCoords; vector GlobalCoords; + @@ -174,4 +176,10 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { void GetInitMaxErrorNode(CGeometry* geometry, CConfig* config); void MPI_Operations(CGeometry* geometry); + + su2double GetError(CGeometry* geometry, CConfig* config); + + su2double* GetNodalError(CGeometry* geometry, CConfig* config, unsigned long iNode, su2double* localError); + + void SetCorrection(CGeometry* geometry); }; \ No newline at end of file diff --git a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp index 3f1e64eeaad..5a33e62b134 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp @@ -41,8 +41,10 @@ class CRadialBasisFunctionNode{ unsigned short marker_idx; /*!< \brief Marker index. */ unsigned long vertex_idx; /*!< \brief Vertex index. */ + su2double error[3]; - public: + + public: /*! * \brief Constructor of the class. @@ -64,4 +66,10 @@ class CRadialBasisFunctionNode{ */ inline unsigned short GetMarker(void){return marker_idx;} + inline void SetError(const su2double* val_error, unsigned short nDim) { + for (unsigned short iDim = 0; iDim < nDim; iDim++) error[iDim] = val_error[iDim]; + } + + inline su2double* GetError(void){ return error;} + }; \ No newline at end of file diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 02c4c4a1f07..85008278991 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -28,6 +28,7 @@ #include "../../include/grid_movement/CRadialBasisFunctionInterpolation.hpp" #include "../../include/interface_interpolation/CRadialBasisFunction.hpp" #include "../../include/toolboxes/geometry_toolbox.hpp" +#include "../../include/adt/CADTPointsOnlyClass.hpp" CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config) : CVolumetricMovement(geometry) { @@ -41,6 +42,8 @@ CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* if(dataReduction){ controlNodes = &greedyNodes; + GreedyTolerance = config->GetRBF_GreedyTolerance(); + GreedyCorrectionFactor = config->GetRBF_GreedyCorrectionFactor(); }else{ controlNodes = &boundaryNodes; } @@ -135,7 +138,6 @@ void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* if(dataReduction){ - GreedyIteration(geometry, config); }else{ //TODO find more elegant way to assign this variable @@ -277,7 +279,6 @@ void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geomet } void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry, CConfig* config){ - /* --- Initialization of the deformation vector ---*/ deformationVector.resize(controlNodes->size()*nDim, 0.0); @@ -289,14 +290,18 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry /*--- Setting nonzero displacements of the moving markers ---*/ for (auto i = 0; i < controlNodes->size(); i++) { - if (config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())) { + if (config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())) { + for (auto iDim = 0; iDim < nDim; iDim++) { deformationVector[i+iDim*controlNodes->size()] = SU2_TYPE::GetValue(geometry->vertex[(*controlNodes)[i]->GetMarker()][(*controlNodes)[i]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); } + }else{ + for (auto iDim = 0; iDim < nDim; iDim++) { + deformationVector[i+iDim*controlNodes->size()] = 0.0; + } } } - #ifdef HAVE_MPI /*--- Gathering all deformation vectors on the master node ---*/ @@ -350,6 +355,7 @@ void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry } #endif + } void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CConfig* config ){ @@ -443,14 +449,13 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo unsigned short iDim; /*--- Vector for storing the coordinate variation ---*/ - su2double var_coord[nDim]; + su2double var_coord[nDim]{0.0}; /*--- Loop over the internal nodes ---*/ for(iNode = 0; iNode < nInternalNodes; iNode++){ - /*--- Loop for contribution of each control node ---*/ for(cNode = 0; cNode < Global_nControlNodes; cNode++){ - + /*--- Determine distance between considered internal and control node ---*/ su2double dist; @@ -477,11 +482,52 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo var_coord[iDim] = 0; } } + + if(dataReduction){ + // setting the coords of the boundary nodes (non-control) in case of greedy + for(iNode = 0; iNode < nBoundaryNodes; iNode++){ + // cout << rank << " " << geometry->nodes->GetGlobalIndex(boundaryNodes[iNode]->GetIndex()) << endl; + for(cNode = 0; cNode < Global_nControlNodes; cNode++){ + + + su2double dist; + + #ifdef HAVE_MPI + dist = 0; + for ( iDim = 0; iDim < nDim; iDim++) dist += pow(GlobalCoords[cNode * nDim + iDim] - geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())[iDim], 2); + dist = sqrt(dist); + #else + dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); + #endif + + // auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); + + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + + for( iDim = 0; iDim < nDim; iDim++){ + var_coord[iDim] += rbf*coefficients[cNode + iDim*Global_nControlNodes]; + } + } + + for(iDim = 0; iDim < nDim; iDim++){ + geometry->nodes->AddCoord(boundaryNodes[iNode]->GetIndex(), iDim, var_coord[iDim]); + var_coord[iDim] = 0; + } + + // auto err = boundaryNodes[iNode]->GetError(); + // // cout << boundaryNodes[iNode]->GetIndex() << '\t' << err[0] << '\t' << err[1] << endl; + // for(iDim = 0; iDim < nDim; iDim++){ + // geometry->nodes->AddCoord(boundaryNodes[iNode]->GetIndex(), iDim, -err[iDim]); + // } + + } + } /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ unsigned long nControlNodes = deformationVector.size()/nDim; // size on master_node is different in case of mpi - for(cNode = 0; cNode < nControlNodes; cNode++){ + for(cNode = 0; cNode < Local_nControlNodes; cNode++){ //TODO for sequential computation Local_nControlNodes should be replaced by nControlNodes + if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ for(iDim = 0; iDim < nDim; iDim++){ #ifdef HAVE_MPI //TODO these are now the same statements @@ -492,6 +538,10 @@ void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CCo } } } + + if(dataReduction){ + SetCorrection(geometry); + } } void CRadialBasisFunctionInterpolation::GreedyIteration(CGeometry* geometry, CConfig* config) { @@ -503,33 +553,31 @@ void CRadialBasisFunctionInterpolation::GreedyIteration(CGeometry* geometry, CCo unsigned short greedyIter = 0; - // Gathering the init greedy nodes - unsigned long MaxErrorNodes[size]; - SU2_MPI::Gather(&MaxErrorNode, 1, MPI_UNSIGNED_LONG, MaxErrorNodes, 1, MPI_UNSIGNED_LONG, MASTER_NODE, SU2_MPI::GetComm()); - + while(MaxError > GreedyTolerance){ - //gathering the coordinates of the selected greedy nodes. This array should be available on the masternode throughout the greedy iteration. - - vector selectedCoords(nDim); // for now a single node is selected; can be an array? - auto coord = geometry->nodes->GetCoord(boundaryNodes[MaxErrorNode]->GetIndex()); + if(rank == MASTER_NODE) cout << "Greedy iteration: " << ++greedyIter << ". Max error: " << MaxError << endl; + // cout << "iteration: " << greedyIter << ". error: " << MaxError << endl; - for(auto iDim = 0; iDim < nDim; iDim++){ - selectedCoords[iDim] = coord[iDim]; - } - vector greedyCoords; - if(rank==MASTER_NODE){ - greedyCoords.resize(nDim*size); - } - SU2_MPI::Gather(selectedCoords.data(), nDim, MPI_DOUBLE, greedyCoords.data(), nDim, MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); - //TODO what if a different number of greedy nodes are selected? + //-------------------- + //TODO collect next statements in AddNode function + greedyNodes.push_back(move(boundaryNodes[MaxErrorNode])); - if (rank == MASTER_NODE){ - for(auto x : greedyCoords){cout << x << endl;} - } + boundaryNodes.erase(boundaryNodes.begin()+MaxErrorNode); + nBoundaryNodes--; + + MPI_Operations(geometry); + + //------------------- + SetDeformationVector(geometry, config); - SU2_MPI::Barrier(SU2_MPI::GetComm()); - SU2_MPI::Abort(SU2_MPI::GetComm(), 0); + SetInterpolationMatrix(geometry, config); + + SolveRBF_System(); + + MaxError = GetError(geometry, config); + + } } void CRadialBasisFunctionInterpolation::GetInitMaxErrorNode(CGeometry* geometry, CConfig* config){ @@ -547,7 +595,11 @@ void CRadialBasisFunctionInterpolation::GetInitMaxErrorNode(CGeometry* geometry, } } MaxError = sqrt(maxDeformation) / ((su2double)config->GetGridDef_Nonlinear_Iter()); - // cout << "rank: " << rank << " Max error node: " << MaxErrorNode << endl; + + #ifdef HAVE_MPI + su2double localMaxError = MaxError; + SU2_MPI::Reduce(&localMaxError, &MaxError, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, SU2_MPI::GetComm()); + #endif } @@ -595,8 +647,106 @@ void CRadialBasisFunctionInterpolation::MPI_Operations(CGeometry* geometry){ }else{ disps[x] = disps[x-1]+LocalCoordsSizes[x-1]; } - } - + } /*--- making global control node coordinates available on all processes ---*/ SU2_MPI::Allgatherv(LocalCoords.data(), localCoordsSize, MPI_DOUBLE, GlobalCoords.data(), LocalCoordsSizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); //TODO local coords can be deleted after this operation -}; \ No newline at end of file + + +}; + + +su2double CRadialBasisFunctionInterpolation::GetError(CGeometry* geometry, CConfig* config){ + unsigned long iNode; + unsigned short iDim; + su2double localError[nDim]; + + su2double error = 0.0, errorMagnitude; + + for(iNode = 0; iNode < nBoundaryNodes; iNode++){ + + boundaryNodes[iNode]->SetError(GetNodalError(geometry, config, iNode, localError), nDim); + + errorMagnitude = GeometryToolbox::Norm(nDim, localError); + if(errorMagnitude > error){ + error = errorMagnitude; + MaxErrorNode = iNode; + } + } + return error; +} + +su2double* CRadialBasisFunctionInterpolation::GetNodalError(CGeometry* geometry, CConfig* config, unsigned long iNode, su2double* localError){ + unsigned short iDim; + su2double* displacement; + su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); + if(config->GetMarker_All_Moving(boundaryNodes[iNode]->GetMarker())){ + displacement = geometry->vertex[boundaryNodes[iNode]->GetMarker()][boundaryNodes[iNode]->GetVertex()]->GetVarCoord(); + // cout << boundaryNodes[iNode]->GetIndex() << '\t' << displacement[0] << '\t' << displacement[1] << endl; + for(iDim = 0; iDim < nDim; iDim++){ + localError[iDim] = -displacement[iDim] * VarIncrement; + } + }else{ + for(iDim = 0; iDim < nDim; iDim++){ + localError[iDim] = 0; + } + } + + for(auto cNode = 0; cNode < Global_nControlNodes; cNode++){ //TODO here + su2double dist; + + #ifdef HAVE_MPI + dist = 0; + for ( iDim = 0; iDim < nDim; iDim++) dist += pow(GlobalCoords[cNode * nDim + iDim] - geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())[iDim], 2); + dist = sqrt(dist); + #else + dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); + #endif + // auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); + + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + + for( iDim = 0; iDim < nDim; iDim++){ + localError[iDim] += rbf*coefficients[cNode + iDim*Global_nControlNodes]; + } + } + // cout << boundaryNodes[iNode]->GetIndex() << '\t' << localError[0] << '\t' << localError[1] << endl; + return localError; +} + +void CRadialBasisFunctionInterpolation::SetCorrection(CGeometry* geometry){ + unsigned long iVertex, iNode, iDim, i, j, pointID; + unsigned long nVertexBound = nBoundaryNodes; + su2double dist; + vector Coord_bound(nDim*nVertexBound); + vector PointIDs(nVertexBound); + int rankID; + + su2double CorrectionRadius = GreedyCorrectionFactor*MaxError; + i = 0; + j = 0; + for(iVertex = 0; iVertex < nVertexBound; iVertex++){ + iNode = boundaryNodes[iVertex]->GetIndex(); + PointIDs[i++] = iVertex; + for(iDim = 0; iDim < nDim; iDim++){ + Coord_bound[j++] = geometry->nodes->GetCoord(iNode, iDim); + } + } + + CADTPointsOnlyClass BoundADT(nDim, nVertexBound, Coord_bound.data(), PointIDs.data(), true); + + for(iNode = 0; iNode < nInternalNodes; iNode++){ + BoundADT.DetermineNearestNode(geometry->nodes->GetCoord(internalNodes[iNode]), dist, pointID, rankID); + auto err = boundaryNodes[pointID]->GetError(); + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, CorrectionRadius, dist)); + for(iDim = 0; iDim < nDim; iDim++){ + geometry->nodes->AddCoord(internalNodes[iNode], iDim, -rbf*err[iDim]); + } + } + + for(iNode = 0; iNode < nBoundaryNodes; iNode++){ + auto err = boundaryNodes[iNode]->GetError(); + for(iDim = 0; iDim < nDim; iDim++){ + geometry->nodes->AddCoord(boundaryNodes[iNode]->GetIndex(), iDim, -err[iDim]); + } + } +} \ No newline at end of file From a4517702dabe4a540df7a49e2880b3244b95fded Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Wed, 3 Jul 2024 22:01:53 +0200 Subject: [PATCH 15/19] Improved version parallel computation --- Common/include/CConfig.hpp | 4 +- .../CRadialBasisFunctionInterpolation.hpp | 194 +++-- .../CRadialBasisFunctionNode.hpp | 36 +- .../CRadialBasisFunctionInterpolation.cpp | 821 ++++++++---------- .../CRadialBasisFunctionNode.cpp | 5 + 5 files changed, 540 insertions(+), 520 deletions(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 18e90aa8581..44e10829ea6 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -4414,13 +4414,13 @@ class CConfig { * \brief Determines use of data reduction methods for RBF mesh deformation. * \return TRUE means that data reduction is used. */ - su2double GetRBF_GreedyTolerance(void) const { return RBF_GreedyTolerance; } + su2double GetRBF_DataRedTolerance(void) const { return RBF_GreedyTolerance; } /*! * \brief Determines use of data reduction methods for RBF mesh deformation. * \return TRUE means that data reduction is used. */ - su2double GetRBF_GreedyCorrectionFactor(void) const { return RBF_GreedyCorrectionFactor; } + su2double GetRBF_DataRedCorrectionFactor(void) const { return RBF_GreedyCorrectionFactor; } /*! * \brief Get the kind of SU2 software component. diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index fefaf53b1a4..4d2e149e28a 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -31,7 +31,7 @@ #include "../../include/toolboxes/CSymmetricMatrix.hpp" /*! - * \class CLinearElasticity + * \class CRadialBasisFunctionInterpolation * \brief Class for moving the volumetric numerical grid using Radial Basis Function interpolation. * \author F. van Steen */ @@ -39,42 +39,18 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { protected: - vector boundaryNodes; /*!< \brief Vector with boundary nodes.*/ - vector internalNodes; /*!< \brief Vector with internal nodes.*/ - unsigned long nBoundaryNodes, /*!< \brief Number of boundary nodes*/ - nInternalNodes; /*!< \brief Number of internal nodes*/ - - vector* controlNodes; /*!< \brief Vector with control nodes*/ + vector* ControlNodes = nullptr; /*!< \brief Vector with control nodes*/ + vector BoundNodes; /*!< \brief Vector with boundary nodes.*/ + vector ReducedControlNodes; /*!< \brief Vector with selected control nodes in data reduction algorithm. */ - vector deformationVector; /*!< \brief Deformation vector.*/ - - vector coefficients; /*!< \brief Control node interpolation coefficients.*/ - CSymmetricMatrix interpMat; /*!< \brief Interpolation matrix.*/ - // su2activematrix interpMat; - - RADIAL_BASIS kindRBF; /*!< \brief Type of Radial Basis Function.*/ - su2double radius; /*!< \brief Support radius of compact Radial Basis Function.*/ - - - /*--- data reduction parameters ---*/ - vector greedyNodes; /*!< \brief Vector with selected control nodes in greedy algorithm. */ - bool dataReduction; /*!< \brief Determines whether data reduction is used. */ - unsigned long MaxErrorNode; - su2double MaxError; - su2double GreedyTolerance; - su2double GreedyCorrectionFactor; - - unsigned long Global_nControlNodes{0}; - /*--- mpi related*/ - - unsigned long Local_nControlNodes; - vector Local_nControlNodesVec; - - // vector LocalCoords; - vector GlobalCoords; + vector CtrlNodeDeformation; /*!< \brief Control Node Deformation.*/ + vector InterpCoeff; /*!< \brief Control node interpolation coefficients.*/ + unsigned long nCtrlNodesGlobal{0}; /*!< \brief Total number of control nodes.*/ + su2activematrix CtrlCoords; /*!< \brief Coordinates of the control nodes.*/ + su2double MaxErrorGlobal{0.0}; /*!< \brief Maximum error data reduction algorithm.*/ public: @@ -99,53 +75,155 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { void SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative); - /*! - * \brief Obtaining the interpolation coefficients based on displacement of the control nodes. + /*! + * \brief Selecting unique set of boundary nodes based on marker information. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. - * \param[in] iNonlinear_Iter - Surface deformation step. */ - void GetInterpolationCoefficients(CGeometry* geometry, CConfig* config, unsigned long iNonlinear_Iter); + void SetBoundNodes(CGeometry* geometry, CConfig* config); + + /*! + * \brief Selecting internal nodes for the volumetric deformation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] internalNode - Internal nodes. + */ + void SetInternalNodes(CGeometry* geometry, CConfig* config, vector& internalNodes); + + /*! + * \brief Assigning the control nodes. + * \param[in] config -Definition of the particular problem. + * */ + + void SetCtrlNodes(CConfig* config); /*! - * \brief Compute the interpolation matrix with Radial Basis Function evaluations. + * \brief Solving the RBF system to obtain the interpolation coefficients. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. */ - void SetInterpolationMatrix(CGeometry* geometry, CConfig* config); + + void SolveRBF_System(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius); /*! - * \brief Build the deformation vector with surface displacements of the control nodes. + * \brief Obtaining the interpolation coefficients of the control nodes. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. */ - void SetDeformationVector(CGeometry* geometry, CConfig* config); + + void GetInterpCoeffs(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius); + /*! - * \brief Selecting unique set of control nodes based on marker information. + * \brief Gathering of all control node coordinates. + * \param[in] geometry - Geometrical definition of the problem. + */ + void SetCtrlNodeCoords(CGeometry* geometry); + + /*! + * \brief Build the deformation vector with surface displacements of the control nodes. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. */ - void SetControlNodes(CGeometry* geometry, CConfig* config); + void SetDeformation(CGeometry* geometry, CConfig* config); /*! - * \brief Selecting internal nodes for the volumetric deformation. + * \brief Computation of the interpolation matrix and inverting in. * \param[in] geometry - Geometrical definition of the problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. + * \param[in] invInterpMat - Inverse of the interpolation matrix. */ - void SetInternalNodes(CGeometry* geometry, CConfig* config); + void ComputeInterpolationMatrix(CGeometry* geometry, const RADIAL_BASIS& type, const su2double radius, su2passivematrix& invInterpMat); /*! - * \brief Solving of the Radial Basis Function interpolation system, yielding the interpolation coefficients + * \brief Computation of interpolation coefficients + * \param[in] invInterpMat - Inverse of interpolation matrix */ - void SolveRBF_System(void); + void ComputeInterpCoeffs(su2passivematrix& invInterpMat); + + /*! + * \brief Finding initial data reduction control nodes based on maximum deformation. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] maxErrorNodeLocal - Local maximum error node. + * \param[in] maxErrorLocal - Local maximum error. + */ + void GetInitMaxErrorNode(CGeometry* geometry, CConfig* config, unsigned long& maxErrorNodeLocal, su2double& maxErrorLocal); + + /*! + * \brief Addition of control node to the reduced set. + * \param[in] maxErrorNode - Node with maximum error to be added. + */ + void AddControlNode(unsigned long maxErrorNode); + + /*! + * \brief Compute global number of control nodes. + */ + void Get_nCtrlNodesGlobal(); + + /*! + * \brief Compute interpolation error. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. + * \param[in] maxErrorNodeLocal - Local maximum error node. + * \param[in] maxErrorLocal - Local maximum error. + */ + void GetInterpError(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius, unsigned long& maxErrorNodeLocal, su2double& maxErrorLocal); + + /*! + * \brief Compute error of single node. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. + * \param[in] iNode - Local node in consideration. + * \param[in] localError - Local error. + */ + void GetNodalError(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius, unsigned long iNode, su2double* localError); - /*! * \brief Updating the grid coordinates. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. + * \param[in] internalNodes - Internal nodes. + */ + void UpdateGridCoord(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius, const vector& internalNodes); + + /*! + * \brief Updating the internal node coordinates. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. + * \param[in] internalNodes - Internal nodes. + */ + void UpdateInternalCoords(CGeometry* geometry, const RADIAL_BASIS& type, const su2double radius, const vector& internalNodes); + + /*! + * \brief Updating the internal node coordinates. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] radius - Support radius of the radial basis function. + */ + void UpdateBoundCoords(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius); + + /*! + * \brief Apply correction to the nonzero error boundary nodes. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] config - Definition of the particular problem. + * \param[in] type - Type of radial basis function. + * \param[in] internalNodes - Internal nodes. */ - void UpdateGridCoord(CGeometry* geometry, CConfig* config); + void SetCorrection(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const vector& internalNodes); /*! * \brief Custom comparison function, for sorting the CRadialBasisFunctionNode objects based on their index. @@ -164,22 +242,4 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { inline static bool Equal(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ return a->GetIndex() == b->GetIndex(); } - - inline static bool Equal2(unsigned long a, unsigned long b){ - return a == b; - }; - - - /*--- Data reduction functions ---*/ - void GreedyIteration(CGeometry* geometry, CConfig* config); - - void GetInitMaxErrorNode(CGeometry* geometry, CConfig* config); - - void MPI_Operations(CGeometry* geometry); - - su2double GetError(CGeometry* geometry, CConfig* config); - - su2double* GetNodalError(CGeometry* geometry, CConfig* config, unsigned long iNode, su2double* localError); - - void SetCorrection(CGeometry* geometry); }; \ No newline at end of file diff --git a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp index 5a33e62b134..0b080b87ad1 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionNode.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionNode.hpp @@ -41,35 +41,49 @@ class CRadialBasisFunctionNode{ unsigned short marker_idx; /*!< \brief Marker index. */ unsigned long vertex_idx; /*!< \brief Vertex index. */ - su2double error[3]; - + su2double error[3]; /*!< \brief Nodal data reduction error; */ public: /*! * \brief Constructor of the class. + * \param[in] idx_val - Local node index. + * \param[in] marker_val - Local marker index. + * \param[in] vertex_val - Local vertex index. */ CRadialBasisFunctionNode(unsigned long idx_val, unsigned short marker_val, unsigned long vertex_val); /*! - * \brief Returns global index. + * \brief Returns local global index. + * \return Local node index. + */ + inline unsigned long GetIndex(){return idx;} + + /*! + * \brief Returns local vertex index. + * \return Local vertex index. */ - inline unsigned long GetIndex(void){return idx;} + inline unsigned long GetVertex(){return vertex_idx;} /*! - * \brief Returns vertex index. + * \brief Returns local marker index. + * \return Local marker index. */ - inline unsigned long GetVertex(void){return vertex_idx;} + inline unsigned short GetMarker(){return marker_idx;} /*! - * \brief Returns marker index. + * \brief Set error of the RBF node. + * \param val_error - Nodal error. + * \param nDim - Number of dimensions. */ - inline unsigned short GetMarker(void){return marker_idx;} inline void SetError(const su2double* val_error, unsigned short nDim) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) error[iDim] = val_error[iDim]; + for (auto iDim = 0u; iDim < nDim; iDim++) error[iDim] = val_error[iDim]; } - inline su2double* GetError(void){ return error;} - + /*! + * \brief Get nodal error. + * \return Nodal error. + */ + inline su2double* GetError(){ return error;} }; \ No newline at end of file diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 85008278991..898033bd405 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -31,36 +31,24 @@ #include "../../include/adt/CADTPointsOnlyClass.hpp" -CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config) : CVolumetricMovement(geometry) { - /*--- Retrieve type of RBF and if applicable its support radius ---*/ - kindRBF = config->GetKindRadialBasisFunction(); - radius = config->GetRadialBasisFunctionParameter(); - - // controlNodes = &boundaryNodes;//TODO start here, for data reduction the greedy nodes should be selected as control nodes and nr of control nodes should be specified. - - dataReduction = config->GetRBF_DataReduction(); - - if(dataReduction){ - controlNodes = &greedyNodes; - GreedyTolerance = config->GetRBF_GreedyTolerance(); - GreedyCorrectionFactor = config->GetRBF_GreedyCorrectionFactor(); - }else{ - controlNodes = &boundaryNodes; - } -} +CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config) : CVolumetricMovement(geometry) {} CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation(void) = default; void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative){ - + + + /*--- Retrieve type of RBF and its support radius ---*/ + + const auto kindRBF = config->GetKindRadialBasisFunction(); + const su2double radius = config->GetRadialBasisFunctionParameter(); su2double MinVolume, MaxVolume; /*--- Retrieving number of deformation steps and screen output from config ---*/ - auto Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); - + const auto Nonlinear_Iter = config->GetGridDef_Nonlinear_Iter(); auto Screen_Output = config->GetDeform_Output(); /*--- Disable the screen output if we're running SU2_CFD ---*/ @@ -68,26 +56,14 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr if (config->GetKind_SU2() == SU2_COMPONENT::SU2_CFD && !Derivative) Screen_Output = false; if (config->GetSmoothGradient()) Screen_Output = true; - - su2double StartTime = SU2_MPI::Wtime(); - /*--- Assigning the node types ---*/ - SetControlNodes(geometry, config); - su2double StopTime = SU2_MPI::Wtime(); - auto UsedTimeCompute = StopTime - StartTime; + /*--- Determining the boundary and internal nodes. Setting the control nodes. ---*/ + SetBoundNodes(geometry, config); - if(rank==MASTER_NODE){ - cout << "Setting control nodes time: " << UsedTimeCompute << " seconds" << endl; - } - - StartTime = SU2_MPI::Wtime(); - SetInternalNodes(geometry, config); - StopTime = SU2_MPI::Wtime(); - UsedTimeCompute = StopTime - StartTime; + vector internalNodes; + SetInternalNodes(geometry, config, internalNodes); - if(rank==MASTER_NODE){ - cout << "Setting internal nodes time: " << UsedTimeCompute << " seconds" << endl; - } + SetCtrlNodes(config); /*--- Looping over the number of deformation iterations ---*/ for (auto iNonlinear_Iter = 0ul; iNonlinear_Iter < Nonlinear_Iter; iNonlinear_Iter++) { @@ -97,20 +73,13 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr ComputeDeforming_Element_Volume(geometry, MinVolume, MaxVolume, Screen_Output); if (rank == MASTER_NODE && Screen_Output) cout << "Min. volume: " << MinVolume << ", max. volume: " << MaxVolume << "." << endl; - - /*--- Obtaining the interpolation coefficients of the control nodes ---*/ - GetInterpolationCoefficients(geometry, config, iNonlinear_Iter); - StartTime = SU2_MPI::Wtime(); + /*--- Solving the RBF system, resulting in the interpolation coefficients ---*/ + SolveRBF_System(geometry, config, kindRBF, radius); + /*--- Updating the coordinates of the grid ---*/ - UpdateGridCoord(geometry, config); - StopTime = SU2_MPI::Wtime(); - UsedTimeCompute = StopTime - StartTime; - - if(rank==MASTER_NODE){ - cout << "Updating grid coords time: " << UsedTimeCompute << " seconds" << endl; - } + UpdateGridCoord(geometry, config, kindRBF, radius, internalNodes); if(UpdateGeo){ UpdateDualGrid(geometry, config); @@ -134,619 +103,591 @@ void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometr } } -void CRadialBasisFunctionInterpolation::GetInterpolationCoefficients(CGeometry* geometry, CConfig* config, unsigned long iNonlinear_Iter){ +void CRadialBasisFunctionInterpolation::SolveRBF_System(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius){ - - if(dataReduction){ - GreedyIteration(geometry, config); - }else{ - //TODO find more elegant way to assign this variable - Global_nControlNodes = controlNodes->size(); - #ifdef HAVE_MPI - MPI_Operations(geometry); - #endif + /*--- In case of data reduction an iterative greedy algorithm is applied + to perform the interpolation with a reduced set of control nodes. + Otherwise with a full set of control nodes. ---*/ + + if(config->GetRBF_DataReduction()){ + /*--- Error tolerance for the data reduction tolerance ---*/ + const su2double dataReductionTolerance = config->GetRBF_DataRedTolerance(); - /*--- Deformation vector only has to be set once ---*/ - su2double StartTime = SU2_MPI::Wtime(); - if(iNonlinear_Iter == 0){ - SetDeformationVector(geometry, config); - } - - su2double StopTime = SU2_MPI::Wtime(); - auto UsedTimeCompute = StopTime - StartTime; - - if(rank==MASTER_NODE){ - cout << "Setting deformation vector time: " << UsedTimeCompute << " seconds" << endl; + /*--- Local maximum error node and corresponding maximum error ---*/ + unsigned long maxErrorNodeLocal; + su2double maxErrorLocal{0}; + + /*--- Obtaining the initial maximum error nodes, which are found based on the maximum applied deformation. */ + if(ControlNodes->empty()){ + GetInitMaxErrorNode(geometry, config, maxErrorNodeLocal, maxErrorLocal); + SU2_MPI::Allreduce(&maxErrorLocal, &MaxErrorGlobal, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); } + /*--- Number of greedy iterations. ---*/ + unsigned short greedyIter = 0; - /*--- Computing the interpolation matrix with RBF evaluations based on Euclidean distance ---*/ - SetInterpolationMatrix(geometry, config); + /*--- While the maximum error is above the tolerance, data reduction algorithm is continued. ---*/ + while(MaxErrorGlobal > dataReductionTolerance || greedyIter == 0){ + + /*--- In case of a nonzero local error, control nodes are added ---*/ + if(maxErrorLocal> 0){ + AddControlNode(maxErrorNodeLocal); + } - /*--- Solving the RBF system to get the interpolation coefficients ---*/ - StartTime = SU2_MPI::Wtime(); - SolveRBF_System(); - StopTime = SU2_MPI::Wtime(); - UsedTimeCompute = StopTime - StartTime; - - if(rank==MASTER_NODE){ - cout << "Obtaining interpolation coefficients time: " << UsedTimeCompute << " seconds" << endl; - } + /*--- Obtaining the global number of control nodes. ---*/ + Get_nCtrlNodesGlobal(); + + /*--- Obtaining the interpolation coefficients. ---*/ + GetInterpCoeffs(geometry, config, type, radius); + + /*--- Determining the interpolation error, of the non-control boundary nodes. ---*/ + GetInterpError(geometry, config, type, radius, maxErrorNodeLocal, maxErrorLocal); + SU2_MPI::Allreduce(&maxErrorLocal, &MaxErrorGlobal, 1, MPI_DOUBLE, MPI_MAX, SU2_MPI::GetComm()); + + if(rank == MASTER_NODE) cout << "Greedy iteration: " << greedyIter << ". Max error: " << MaxErrorGlobal << ". Global nr. of ctrl nodes: " << nCtrlNodesGlobal << "\n" << endl; + greedyIter++; + + } + }else{ + + /*--- Obtaining the interpolation coefficients. ---*/ + GetInterpCoeffs(geometry, config, type, radius); } +} + +void CRadialBasisFunctionInterpolation::GetInterpCoeffs(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius){ + + /*--- Obtaining the control nodes coordinates and distributing over all processes. ---*/ + SetCtrlNodeCoords(geometry); + /*--- Obtaining the deformation of the control nodes. ---*/ + SetDeformation(geometry, config); + + /*--- Computation of the (inverse) interpolation matrix. ---*/ + su2passivematrix invInterpMat; + ComputeInterpolationMatrix(geometry, type, radius, invInterpMat); + + /*--- Obtaining the interpolation coefficients. ---*/ + ComputeInterpCoeffs(invInterpMat); } -void CRadialBasisFunctionInterpolation::SetControlNodes(CGeometry* geometry, CConfig* config){ +void CRadialBasisFunctionInterpolation::SetBoundNodes(CGeometry* geometry, CConfig* config){ - unsigned short iMarker; - unsigned long iVertex, iNode; - - /*--- Storing of the node, marker and vertex information ---*/ + /*--- Storing of the local node, marker and vertex information of the boundary nodes ---*/ /*--- Looping over the markers ---*/ - for (iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { + for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); iMarker++) { /*--- Checking if not internal or send/receive marker ---*/ if (!config->GetMarker_All_Deform_Mesh_Internal(iMarker) && !config->GetMarker_All_SendRecv(iMarker)) { /*--- Looping over the vertices of marker ---*/ - for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + for (auto iVertex = 0ul; iVertex < geometry->nVertex[iMarker]; iVertex++) { /*--- Node in consideration ---*/ - iNode = geometry->vertex[iMarker][iVertex]->GetNode(); + auto iNode = geometry->vertex[iMarker][iVertex]->GetNode(); /*--- Check whether node is part of the subdomain and not shared with a receiving marker (for parallel computation)*/ if (geometry->nodes->GetDomain(iNode)) { - boundaryNodes.push_back(new CRadialBasisFunctionNode(iNode, iMarker, iVertex)); + BoundNodes.push_back(new CRadialBasisFunctionNode(iNode, iMarker, iVertex)); } } } } /*--- Sorting of the boundary nodes based on their index ---*/ - sort(boundaryNodes.begin(), boundaryNodes.end(), Compare); + sort(BoundNodes.begin(), BoundNodes.end(), Compare); - /*--- Obtaining unique set of boundary nodes ---*/ - boundaryNodes.resize(std::distance(boundaryNodes.begin(), unique(boundaryNodes.begin(), boundaryNodes.end(), Equal))); - - /*--- Updating the number of boundary nodes ---*/ - nBoundaryNodes = boundaryNodes.size(); + /*--- Obtaining unique set ---*/ + BoundNodes.resize(std::distance(BoundNodes.begin(), unique(BoundNodes.begin(), BoundNodes.end(), Equal))); } -void CRadialBasisFunctionInterpolation::SetInterpolationMatrix(CGeometry* geometry, CConfig* config){ - su2double StartTime = SU2_MPI::Wtime(); - unsigned long iNode, jNode; - unsigned long interpMatSize; +void CRadialBasisFunctionInterpolation::SetCtrlNodes(CConfig* config){ + + /*--- Assigning the control nodes based on whether data reduction is applied or not. ---*/ + if(config->GetRBF_DataReduction()){ + + /*--- Control nodes are an empty set ---*/ + ControlNodes = &ReducedControlNodes; + }else{ - /*--- In case of parallel computation, the interpolation coefficients are computed on the master node. - In order to do so the coordinates of all control nodes are collected on the master node ---*/ + /*--- Control nodes are the boundary nodes ---*/ + ControlNodes = &BoundNodes; + } + /*--- Obtaining the total number of control nodes. ---*/ + Get_nCtrlNodesGlobal(); + +}; + +void CRadialBasisFunctionInterpolation::ComputeInterpolationMatrix(CGeometry* geometry, const RADIAL_BASIS& type, const su2double radius, su2passivematrix& invInterpMat){ + + /*--- In case of parallel computation, the interpolation coefficients are computed on the master node ---*/ - if(rank == MASTER_NODE){ + CSymmetricMatrix interpMat; + /*--- Initialization of the interpolation matrix ---*/ - interpMat.Initialize(Global_nControlNodes); + interpMat.Initialize(nCtrlNodesGlobal); /*--- Construction of the interpolation matrix. Since this matrix is symmetric only upper halve has to be considered ---*/ /*--- Looping over the target nodes ---*/ - for(iNode = 0; iNode < Global_nControlNodes; iNode++ ){ + for( auto iNode = 0ul; iNode < nCtrlNodesGlobal; iNode++ ){ /*--- Looping over the control nodes ---*/ - for (jNode = iNode; jNode < Global_nControlNodes; jNode++){ + for ( auto jNode = iNode; jNode < nCtrlNodesGlobal; jNode++){ /*--- Distance between nodes ---*/ - #ifdef HAVE_MPI - su2double dist(0); - - for (unsigned short i = 0; i < nDim; i++) dist += pow(GlobalCoords[iNode*nDim+i] - GlobalCoords[jNode*nDim+i], 2); - dist = sqrt(dist); - - #else - auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()), geometry->nodes->GetCoord((*controlNodes)[jNode]->GetIndex())); - #endif + auto dist = GeometryToolbox::Distance(nDim, CtrlCoords[iNode*nDim], CtrlCoords[jNode*nDim]); + /*--- Evaluation of RBF ---*/ - interpMat(iNode, jNode) = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + interpMat(iNode, jNode) = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(type, radius, dist)); } } - // /*--- Obtaining lower halve using symmetry ---*/ - const bool kernelIsSPD = (kindRBF == RADIAL_BASIS::WENDLAND_C2) || (kindRBF == RADIAL_BASIS::GAUSSIAN) || - (kindRBF == RADIAL_BASIS::INV_MULTI_QUADRIC); - - - su2double StopTime = SU2_MPI::Wtime(); - auto UsedTimeCompute = StopTime - StartTime; - - - cout << "setting interp matrix time: " << UsedTimeCompute << " seconds" << endl; - // SU2_MPI::Send(interpMat.data(), interpMat.size(), MPI_DOUBLE, rank, MASTER_NODE, SU2_MPI::GetComm()); - StartTime = SU2_MPI::Wtime(); + /*--- Obtaining lower halve using symmetry ---*/ + const bool kernelIsSPD = (type == RADIAL_BASIS::WENDLAND_C2) || (type == RADIAL_BASIS::GAUSSIAN) || + (type == RADIAL_BASIS::INV_MULTI_QUADRIC); - + /*--- inverting the interpolation matrix ---*/ interpMat.Invert(kernelIsSPD); - StopTime = SU2_MPI::Wtime(); - UsedTimeCompute = StopTime - StartTime; - - - cout << "Inverting matrix time: " << UsedTimeCompute << " seconds" << endl; - + invInterpMat = interpMat.StealData(); } } -void CRadialBasisFunctionInterpolation::SetDeformationVector(CGeometry* geometry, CConfig* config){ +void CRadialBasisFunctionInterpolation::SetDeformation(CGeometry* geometry, CConfig* config){ + /* --- Initialization of the deformation vector ---*/ - deformationVector.resize(controlNodes->size()*nDim, 0.0); + CtrlNodeDeformation.resize(ControlNodes->size()*nDim, 0.0); /*--- If requested (no by default) impose the surface deflections in increments and solve the grid deformation with successive small deformations. ---*/ - su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); + const su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); - /*--- Setting nonzero displacements of the moving markers ---*/ - for (auto i = 0; i < controlNodes->size(); i++) { + /*--- Loop over the control nodes ---*/ + for (auto iNode = 0ul; iNode < ControlNodes->size(); iNode++) { - if (config->GetMarker_All_Moving((*controlNodes)[i]->GetMarker())) { - - for (auto iDim = 0; iDim < nDim; iDim++) { - deformationVector[i+iDim*controlNodes->size()] = SU2_TYPE::GetValue(geometry->vertex[(*controlNodes)[i]->GetMarker()][(*controlNodes)[i]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); + /*--- Setting nonzero displacement of the moving markers, else setting zero displacement for static markers---*/ + if (config->GetMarker_All_Moving((*ControlNodes)[iNode]->GetMarker())) { + for (auto iDim = 0u; iDim < nDim; iDim++) { + CtrlNodeDeformation[iNode*nDim + iDim] = SU2_TYPE::GetValue(geometry->vertex[(*ControlNodes)[iNode]->GetMarker()][(*ControlNodes)[iNode]->GetVertex()]->GetVarCoord()[iDim] * VarIncrement); } - }else{ - for (auto iDim = 0; iDim < nDim; iDim++) { - deformationVector[i+iDim*controlNodes->size()] = 0.0; + } + + else{ + for (auto iDim = 0u; iDim < nDim; iDim++) { + CtrlNodeDeformation[iNode*nDim + iDim] = 0.0; } } } - + + /*--- In case of a parallel computation, the deformation of all control nodes is send to the master process ---*/ #ifdef HAVE_MPI + /*--- Local number of control nodes ---*/ + unsigned long Local_nControlNodes = ControlNodes->size(); + + /*--- Array containing the local number of control nodes ---*/ + unsigned long Local_nControlNodesArr[size]; + + /*--- gathering local control node coordinate sizes on all processes. ---*/ + SU2_MPI::Allgather(&Local_nControlNodes, 1, MPI_UNSIGNED_LONG, Local_nControlNodesArr, 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); + /*--- Gathering all deformation vectors on the master node ---*/ if(rank==MASTER_NODE){ /*--- resizing the global deformation vector ---*/ - deformationVector.resize(Global_nControlNodes*nDim); + CtrlNodeDeformation.resize(nCtrlNodesGlobal*nDim); /*--- Receiving the local deformation vector from other processes ---*/ unsigned long start_idx = 0; for (auto iProc = 0; iProc < size; iProc++) { if (iProc != MASTER_NODE) { - SU2_MPI::Recv(&deformationVector[0] + start_idx, Local_nControlNodesVec[iProc]*nDim, MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); // TODO can status ignore be used? + SU2_MPI::Recv(&CtrlNodeDeformation[0] + start_idx, Local_nControlNodesArr[iProc]*nDim, MPI_DOUBLE, iProc, 0, SU2_MPI::GetComm(), MPI_STATUS_IGNORE); } - start_idx += Local_nControlNodesVec[iProc]*nDim; + start_idx += Local_nControlNodesArr[iProc]*nDim; } }else{ /*--- Sending the local deformation vector to the master node ---*/ - SU2_MPI::Send(deformationVector.data(), Local_nControlNodes*nDim, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); - + SU2_MPI::Send(CtrlNodeDeformation.data(), Local_nControlNodes*nDim, MPI_DOUBLE, MASTER_NODE, 0, SU2_MPI::GetComm()); } - - /*--- The global deformation vector is now ordered as d_1, d_2, ..., d_n, where n is the number of processes. - Here the deformation vector is reordered to obtain an order x_1, ..., x_n, y_1, ..., y_n, z_1, ..., z_n, - where x_n is the deformation in x of deformation vector n */ - if(rank == MASTER_NODE){ - - - for (unsigned short iDim = nDim-1; iDim > 0; iDim--) { - - unsigned long start_idx = 0; - - for (unsigned short processor = 0; processor < SU2_MPI::GetSize(); processor++) { - - if ( processor == 0){ - start_idx += Local_nControlNodesVec[processor]; - } - else{ - start_idx += (Local_nControlNodesVec[processor-1]*(iDim-1) + Local_nControlNodesVec[processor]); - } - - /*--- inserting part of vector at end of deformationVector ---*/ - deformationVector.insert(deformationVector.end(), deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+Local_nControlNodesVec[processor]); - - /*--- erasing moved part of the vector ---*/ - deformationVector.erase(deformationVector.begin()+start_idx, deformationVector.begin()+start_idx+Local_nControlNodesVec[processor]); - } - } - } - #endif - } -void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CConfig* config ){ - - unsigned long node; - - /*--- resizing the internal nodes vector ---*/ - nInternalNodes = geometry->GetnPoint();// - nBoundaryNodes; // vector has max size of nPoints - internalNodes.resize(nInternalNodes); - +void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CConfig* config, vector& internalNodes){ /*--- Looping over all nodes and check if part of domain and not on boundary ---*/ - unsigned long idx_cnt = 0, idx_control = 0; - for (unsigned long iNode = 0; iNode < geometry->GetnPoint(); iNode++) { + for (auto iNode = 0ul; iNode < geometry->GetnPoint(); iNode++) { if (!geometry->nodes->GetBoundary(iNode)) { - internalNodes[idx_cnt++] = iNode; + internalNodes.push_back(iNode); } } - + /*--- In case of a parallel computation, the nodes on the send/receive markers are included as internal nodes + if they are not already a boundary node with known deformation ---*/ #ifdef HAVE_MPI /*--- Looping over the markers ---*/ - for (unsigned short iMarker = 0; iMarker < geometry->GetnMarker(); iMarker++) { + for (auto iMarker = 0u; iMarker < geometry->GetnMarker(); iMarker++) { /*--- If send or receive marker ---*/ if (config->GetMarker_All_SendRecv(iMarker)) { /*--- Loop over marker vertices ---*/ - for (unsigned long iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { + for (auto iVertex = 0ul; iVertex < geometry->nVertex[iMarker]; iVertex++) { /*--- Local node index ---*/ - node = geometry->vertex[iMarker][iVertex]->GetNode(); + auto iNode = geometry->vertex[iMarker][iVertex]->GetNode(); // /*--- if not among the boundary nodes ---*/ - if (find_if (boundaryNodes.begin(), boundaryNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == node;}) == boundaryNodes.end()) { - internalNodes[idx_cnt++] = node; + if (find_if (BoundNodes.begin(), BoundNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == iNode;}) == BoundNodes.end()) { + internalNodes.push_back(iNode); } } } } /*--- sorting of the local indices ---*/ - sort(internalNodes.begin(), internalNodes.begin() + idx_cnt); + sort(internalNodes.begin(), internalNodes.end()); /*--- Obtaining unique set of internal nodes ---*/ - internalNodes.resize(std::distance(internalNodes.begin(), unique(internalNodes.begin(), internalNodes.begin() + idx_cnt))); - - /*--- Updating the number of internal nodes ---*/ - nInternalNodes = internalNodes.size(); - - #else - nInternalNodes = idx_cnt; - internalNodes.resize(nInternalNodes); + internalNodes.resize(std::distance(internalNodes.begin(), unique(internalNodes.begin(), internalNodes.end()))); #endif } -void CRadialBasisFunctionInterpolation::SolveRBF_System(){ - auto rank = SU2_MPI::GetRank(); - - unsigned long nControlNodes_local = controlNodes->size(); - - #ifdef HAVE_MPI - unsigned long size; - SU2_MPI::Allreduce(&nControlNodes_local, &size, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); - #else - size = controlNodes->size(); - #endif +void CRadialBasisFunctionInterpolation::ComputeInterpCoeffs(su2passivematrix& invInterpMat){ + /*--- resizing the interpolation coefficient vector ---*/ - coefficients.resize(nDim*size); + InterpCoeff.resize(nDim*nCtrlNodesGlobal); + /*--- Coefficients are found on the master process. + Resulting coefficient is found by summing the multiplications of inverse interpolation matrix entries with deformation ---*/ if(rank == MASTER_NODE){ - /*--- Looping through the dimensions in order to find the interpolation coefficients for each direction ---*/ - unsigned short iDim; - for(iDim = 0; iDim < nDim; iDim++){ - interpMat.MatVecMult(deformationVector.begin()+iDim*size, coefficients.begin()+iDim*size); - } - } + for(auto iNode = 0ul; iNode < nCtrlNodesGlobal; iNode++){ + for (auto iDim = 0u; iDim < nDim; iDim++){ + InterpCoeff[iNode*nDim + iDim] = 0; + for (auto jNode = 0ul; jNode < nCtrlNodesGlobal; jNode++){ + InterpCoeff[iNode * nDim + iDim] += invInterpMat(iNode,jNode) * CtrlNodeDeformation[jNode*nDim+ iDim]; + } + } + } + } + + /*--- Broadcasting the interpolation coefficients ---*/ #ifdef HAVE_MPI - SU2_MPI::Bcast(coefficients.data(), coefficients.size(), MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); - #endif + SU2_MPI::Bcast(InterpCoeff.data(), InterpCoeff.size(), MPI_DOUBLE, MASTER_NODE, SU2_MPI::GetComm()); + #endif } -void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CConfig* config){ +void CRadialBasisFunctionInterpolation::UpdateGridCoord(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius, const vector& internalNodes){ + if(rank == MASTER_NODE){ cout << "updating the grid coordinates" << endl; } - unsigned long iNode, cNode; - unsigned short iDim; + + /*--- Update of internal node coordinates ---*/ + UpdateInternalCoords(geometry, type, radius, internalNodes); - /*--- Vector for storing the coordinate variation ---*/ + /*--- Update of boundary node coordinates ---*/ + UpdateBoundCoords(geometry, config, type, radius); + + /*--- In case of data reduction, perform the correction for nonzero error nodes ---*/ + if(config->GetRBF_DataReduction() && BoundNodes.size() > 0){ + SetCorrection(geometry, config, type, internalNodes); + } +} + +void CRadialBasisFunctionInterpolation::UpdateInternalCoords(CGeometry* geometry, const RADIAL_BASIS& type, const su2double radius, const vector& internalNodes){ + + /*--- Vector for storing the coordinate variation ---*/ su2double var_coord[nDim]{0.0}; /*--- Loop over the internal nodes ---*/ - for(iNode = 0; iNode < nInternalNodes; iNode++){ + for(auto iNode = 0ul; iNode < internalNodes.size(); iNode++){ + /*--- Loop for contribution of each control node ---*/ - for(cNode = 0; cNode < Global_nControlNodes; cNode++){ + for(auto jNode = 0ul; jNode < nCtrlNodesGlobal; jNode++){ /*--- Determine distance between considered internal and control node ---*/ - su2double dist; - - #ifdef HAVE_MPI - dist = 0; - for ( iDim = 0; iDim < nDim; iDim++) dist += pow(GlobalCoords[cNode * nDim + iDim] - geometry->nodes->GetCoord(internalNodes[iNode])[iDim], 2); - dist = sqrt(dist); - #else - dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(internalNodes[iNode])); - #endif - + auto dist = GeometryToolbox::Distance(nDim, CtrlCoords[jNode*nDim], geometry->nodes->GetCoord(internalNodes[iNode])); + /*--- Evaluate RBF based on distance ---*/ - auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(type, radius, dist)); /*--- Add contribution to total coordinate variation ---*/ - for( iDim = 0; iDim < nDim; iDim++){ - var_coord[iDim] += rbf*coefficients[cNode + iDim*Global_nControlNodes]; + for(auto iDim = 0u; iDim < nDim; iDim++){ + var_coord[iDim] += rbf*InterpCoeff[jNode * nDim + iDim]; } } /*--- Apply the coordinate variation and resetting the var_coord vector to zero ---*/ - for(iDim = 0; iDim < nDim; iDim++){ + for(auto iDim = 0u; iDim < nDim; iDim++){ geometry->nodes->AddCoord(internalNodes[iNode], iDim, var_coord[iDim]); var_coord[iDim] = 0; } } +} - if(dataReduction){ - // setting the coords of the boundary nodes (non-control) in case of greedy - for(iNode = 0; iNode < nBoundaryNodes; iNode++){ - // cout << rank << " " << geometry->nodes->GetGlobalIndex(boundaryNodes[iNode]->GetIndex()) << endl; - for(cNode = 0; cNode < Global_nControlNodes; cNode++){ - - - su2double dist; +void CRadialBasisFunctionInterpolation::UpdateBoundCoords(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius){ + + /*--- Vector for storing the coordinate variation ---*/ + su2double var_coord[nDim]{0.0}; + + /*--- In case of data reduction, the non-control boundary nodes are treated as if they where internal nodes ---*/ + if(config->GetRBF_DataReduction()){ - #ifdef HAVE_MPI - dist = 0; - for ( iDim = 0; iDim < nDim; iDim++) dist += pow(GlobalCoords[cNode * nDim + iDim] - geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())[iDim], 2); - dist = sqrt(dist); - #else - dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); - #endif - - // auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); + /*--- Looping over the non selected boundary nodes ---*/ + for(auto iNode = 0ul; iNode < BoundNodes.size(); iNode++){ + + /*--- Finding contribution of each control node ---*/ + for( auto jNode = 0ul; jNode < nCtrlNodesGlobal; jNode++){ + + /*--- Distance of non-selected boundary node to control node ---*/ + auto dist = GeometryToolbox::Distance(nDim, CtrlCoords[jNode*nDim], geometry->nodes->GetCoord(BoundNodes[iNode]->GetIndex())); + + /*--- Evaluation of the radial basis function based on the distance ---*/ + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(type, radius, dist)); - auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); - - for( iDim = 0; iDim < nDim; iDim++){ - var_coord[iDim] += rbf*coefficients[cNode + iDim*Global_nControlNodes]; + /*--- Computing and add the resulting coordinate variation ---*/ + for(auto iDim = 0u; iDim < nDim; iDim++){ + var_coord[iDim] += rbf*InterpCoeff[jNode * nDim + iDim]; + } } - } - - for(iDim = 0; iDim < nDim; iDim++){ - geometry->nodes->AddCoord(boundaryNodes[iNode]->GetIndex(), iDim, var_coord[iDim]); - var_coord[iDim] = 0; - } - // auto err = boundaryNodes[iNode]->GetError(); - // // cout << boundaryNodes[iNode]->GetIndex() << '\t' << err[0] << '\t' << err[1] << endl; - // for(iDim = 0; iDim < nDim; iDim++){ - // geometry->nodes->AddCoord(boundaryNodes[iNode]->GetIndex(), iDim, -err[iDim]); - // } + /*--- Applying the coordinate variation and resetting the var_coord vector*/ + for(auto iDim = 0u; iDim < nDim; iDim++){ + geometry->nodes->AddCoord(BoundNodes[iNode]->GetIndex(), iDim, var_coord[iDim]); + var_coord[iDim] = 0; + } } } /*--- Applying the surface deformation, which are stored in the deformation vector ---*/ - - unsigned long nControlNodes = deformationVector.size()/nDim; // size on master_node is different in case of mpi - for(cNode = 0; cNode < Local_nControlNodes; cNode++){ //TODO for sequential computation Local_nControlNodes should be replaced by nControlNodes - - if(config->GetMarker_All_Moving((*controlNodes)[cNode]->GetMarker())){ - for(iDim = 0; iDim < nDim; iDim++){ - #ifdef HAVE_MPI //TODO these are now the same statements - geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nControlNodes]); - #else - geometry->nodes->AddCoord((*controlNodes)[cNode]->GetIndex(), iDim, deformationVector[cNode + iDim*nControlNodes]); - #endif + for(auto jNode = 0ul; jNode < ControlNodes->size(); jNode++){ + if(config->GetMarker_All_Moving((*ControlNodes)[jNode]->GetMarker())){ + for(auto iDim = 0u; iDim < nDim; iDim++){ + geometry->nodes->AddCoord((*ControlNodes)[jNode]->GetIndex(), iDim, CtrlNodeDeformation[jNode*nDim + iDim]); } } - } - - if(dataReduction){ - SetCorrection(geometry); - } + } } -void CRadialBasisFunctionInterpolation::GreedyIteration(CGeometry* geometry, CConfig* config) { - if (rank == MASTER_NODE) { - cout << "Starting greedy iteration..." << endl; - } - - GetInitMaxErrorNode(geometry, config); - - unsigned short greedyIter = 0; - - while(MaxError > GreedyTolerance){ - - if(rank == MASTER_NODE) cout << "Greedy iteration: " << ++greedyIter << ". Max error: " << MaxError << endl; - // cout << "iteration: " << greedyIter << ". error: " << MaxError << endl; - //-------------------- - //TODO collect next statements in AddNode function - greedyNodes.push_back(move(boundaryNodes[MaxErrorNode])); +void CRadialBasisFunctionInterpolation::GetInitMaxErrorNode(CGeometry* geometry, CConfig* config, unsigned long& maxErrorNodeLocal, su2double& maxErrorLocal){ - boundaryNodes.erase(boundaryNodes.begin()+MaxErrorNode); - nBoundaryNodes--; + /*--- Set max error to zero ---*/ + maxErrorLocal = 0.0; - MPI_Operations(geometry); - - //------------------- - - SetDeformationVector(geometry, config); - - SetInterpolationMatrix(geometry, config); + /*--- Loop over the nodes ---*/ + for(auto iNode = 0ul; iNode < BoundNodes.size(); iNode++){ - SolveRBF_System(); - - MaxError = GetError(geometry, config); - - } -} + /*--- Compute to squared norm of the deformation ---*/ + su2double normSquaredDeformation = GeometryToolbox::SquaredNorm(nDim, geometry->vertex[BoundNodes[iNode]->GetMarker()][BoundNodes[iNode]->GetVertex()]->GetVarCoord()); -void CRadialBasisFunctionInterpolation::GetInitMaxErrorNode(CGeometry* geometry, CConfig* config){ - unsigned short iNode; - - su2double maxDeformation = 0.0; - su2double normSquaredDeformation; - su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); - - for(iNode = 0; iNode < nBoundaryNodes; iNode++){ - normSquaredDeformation = GeometryToolbox::SquaredNorm(nDim, geometry->vertex[boundaryNodes[iNode]->GetMarker()][boundaryNodes[iNode]->GetVertex()]->GetVarCoord()); - if(normSquaredDeformation > maxDeformation){ - maxDeformation = normSquaredDeformation; - MaxErrorNode = iNode; + /*--- In case squared norm deformation is larger than the error, update the error ---*/ + if(normSquaredDeformation > maxErrorLocal){ + maxErrorLocal = normSquaredDeformation; + maxErrorNodeLocal = iNode; } } - MaxError = sqrt(maxDeformation) / ((su2double)config->GetGridDef_Nonlinear_Iter()); - #ifdef HAVE_MPI - su2double localMaxError = MaxError; - SU2_MPI::Reduce(&localMaxError, &MaxError, 1, MPI_DOUBLE, MPI_MAX, MASTER_NODE, SU2_MPI::GetComm()); - #endif + /*--- Account for the possibility of applying the deformation in multiple steps ---*/ + maxErrorLocal = sqrt(maxErrorLocal) / ((su2double)config->GetGridDef_Nonlinear_Iter()); } -void CRadialBasisFunctionInterpolation::MPI_Operations(CGeometry* geometry){ - Local_nControlNodes = controlNodes->size(); - - Local_nControlNodesVec.resize(size); - - /*--- gathering local control node coordinate sizes on all processes. ---*/ - SU2_MPI::Allgather(&Local_nControlNodes, 1, MPI_UNSIGNED_LONG, Local_nControlNodesVec.data(), 1, MPI_UNSIGNED_LONG, SU2_MPI::GetComm()); - - - Global_nControlNodes = 0; - for( auto& n : Local_nControlNodesVec) Global_nControlNodes += n; - - /*--- array containing the global control node coordinates. ---*/ - GlobalCoords.resize(Global_nControlNodes*nDim); +void CRadialBasisFunctionInterpolation::SetCtrlNodeCoords(CGeometry* geometry){ + /*--- The coordinates of all control nodes are made available on all processes ---*/ - /*--- array containing the local control node coordinates. ---*/ - vector LocalCoords(nDim*Local_nControlNodes); - + /*--- resizing the matrix containing the global control node coordinates ---*/ + CtrlCoords.resize(nCtrlNodesGlobal*nDim); - /*--- storing local control node coordinates ---*/ - for(unsigned long iNode = 0; iNode < controlNodes->size(); iNode++){ - auto coord = geometry->nodes->GetCoord((*controlNodes)[iNode]->GetIndex()); - for ( unsigned short iDim = 0 ; iDim < nDim; iDim++ ){ - LocalCoords[ iNode * nDim + iDim ] = coord[iDim]; + /*--- Array containing the local control node coordinates ---*/ + su2double localCoords[nDim*ControlNodes->size()]; + + /*--- Storing local control node coordinates ---*/ + for(auto iNode = 0ul; iNode < ControlNodes->size(); iNode++){ + auto coord = geometry->nodes->GetCoord((*ControlNodes)[iNode]->GetIndex()); + for ( auto iDim = 0u ; iDim < nDim; iDim++ ){ + localCoords[ iNode * nDim + iDim ] = coord[iDim]; } } - /*--- array containing size of local control node coordinates. ---*/ - int LocalCoordsSizes[SU2_MPI::GetSize()]; - - int localCoordsSize = LocalCoords.size(); - /*--- gathering local control node coordinate sizes on all processes. ---*/ + /*--- Gathering local control node coordinate sizes on all processes. ---*/ + int LocalCoordsSizes[size]; + int localCoordsSize = nDim*ControlNodes->size(); SU2_MPI::Allgather(&localCoordsSize, 1, MPI_INT, LocalCoordsSizes, 1, MPI_INT, SU2_MPI::GetComm()); - - - /*--- array containing the starting indices for the allgatherv operation*/ - int disps[SU2_MPI::GetSize()]; - - for(auto x = 0; x < SU2_MPI::GetSize(); x++){ - if(x == 0){ - disps[x] = 0; - }else{ - disps[x] = disps[x-1]+LocalCoordsSizes[x-1]; - } - } - /*--- making global control node coordinates available on all processes ---*/ - SU2_MPI::Allgatherv(LocalCoords.data(), localCoordsSize, MPI_DOUBLE, GlobalCoords.data(), LocalCoordsSizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); //TODO local coords can be deleted after this operation + /*--- Array containing the starting indices for the allgatherv operation */ + int disps[SU2_MPI::GetSize()] = {0}; + for(auto iProc = 1; iProc < SU2_MPI::GetSize(); iProc++){ + disps[iProc] = disps[iProc-1]+LocalCoordsSizes[iProc-1]; + } + + /*--- Distributing global control node coordinates among all processes ---*/ + SU2_MPI::Allgatherv(&localCoords, localCoordsSize, MPI_DOUBLE, CtrlCoords.data(), LocalCoordsSizes, disps, MPI_DOUBLE, SU2_MPI::GetComm()); }; -su2double CRadialBasisFunctionInterpolation::GetError(CGeometry* geometry, CConfig* config){ - unsigned long iNode; - unsigned short iDim; +void CRadialBasisFunctionInterpolation::GetInterpError(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius, unsigned long& maxErrorNodeLocal, su2double& maxErrorLocal){ + /*--- Array containing the local error ---*/ su2double localError[nDim]; - su2double error = 0.0, errorMagnitude; + /*--- Magnitude of the local maximum error ---*/ + maxErrorLocal = 0.0; - for(iNode = 0; iNode < nBoundaryNodes; iNode++){ + /*--- Loop over non-selected boundary nodes ---*/ + for(auto iNode = 0ul; iNode < BoundNodes.size(); iNode++){ - boundaryNodes[iNode]->SetError(GetNodalError(geometry, config, iNode, localError), nDim); + /*--- Compute nodal error ---*/ + GetNodalError(geometry, config, type, radius, iNode, localError); - errorMagnitude = GeometryToolbox::Norm(nDim, localError); - if(errorMagnitude > error){ - error = errorMagnitude; - MaxErrorNode = iNode; + /*--- Setting error ---*/ + BoundNodes[iNode]->SetError(localError, nDim); + + /*--- Compute error magnitude and update local maximum error if necessary ---*/ + su2double errorMagnitude = GeometryToolbox::Norm(nDim, localError); + if(errorMagnitude > maxErrorLocal){ + maxErrorLocal = errorMagnitude; + maxErrorNodeLocal = iNode; } } - return error; } -su2double* CRadialBasisFunctionInterpolation::GetNodalError(CGeometry* geometry, CConfig* config, unsigned long iNode, su2double* localError){ - unsigned short iDim; - su2double* displacement; - su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); - if(config->GetMarker_All_Moving(boundaryNodes[iNode]->GetMarker())){ - displacement = geometry->vertex[boundaryNodes[iNode]->GetMarker()][boundaryNodes[iNode]->GetVertex()]->GetVarCoord(); - // cout << boundaryNodes[iNode]->GetIndex() << '\t' << displacement[0] << '\t' << displacement[1] << endl; - for(iDim = 0; iDim < nDim; iDim++){ +void CRadialBasisFunctionInterpolation::GetNodalError(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const su2double radius, unsigned long iNode, su2double* localError){ + + /*--- If requested (no by default) impose the surface deflections in increments ---*/ + const su2double VarIncrement = 1.0 / ((su2double)config->GetGridDef_Nonlinear_Iter()); + + /*--- If node is part of a moving boundary then the error is defined as the difference + between the found and prescribed displacements. Thus, here the displacement is substracted from the error ---*/ + if(config->GetMarker_All_Moving(BoundNodes[iNode]->GetMarker())){ + auto displacement = geometry->vertex[BoundNodes[iNode]->GetMarker()][BoundNodes[iNode]->GetVertex()]->GetVarCoord(); + + for(auto iDim = 0u; iDim < nDim; iDim++){ localError[iDim] = -displacement[iDim] * VarIncrement; } }else{ - for(iDim = 0; iDim < nDim; iDim++){ - localError[iDim] = 0; + for(auto iDim = 0u; iDim < nDim; iDim++){ + localError[iDim] = 0; } } - for(auto cNode = 0; cNode < Global_nControlNodes; cNode++){ //TODO here - su2double dist; + /*--- Resulting displacement from the RBF interpolation is added to the error ---*/ + + /*--- Finding contribution of each control node ---*/ + for(auto jNode = 0ul; jNode < nCtrlNodesGlobal; jNode++){ - #ifdef HAVE_MPI - dist = 0; - for ( iDim = 0; iDim < nDim; iDim++) dist += pow(GlobalCoords[cNode * nDim + iDim] - geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())[iDim], 2); - dist = sqrt(dist); - #else - dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); - #endif - // auto dist = GeometryToolbox::Distance(nDim, geometry->nodes->GetCoord((*controlNodes)[cNode]->GetIndex()), geometry->nodes->GetCoord(boundaryNodes[iNode]->GetIndex())); + /*--- Distance between non-selected boundary node and control node ---*/ + auto dist = GeometryToolbox::Distance(nDim, CtrlCoords[jNode *nDim], geometry->nodes->GetCoord(BoundNodes[iNode]->GetIndex())); - auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, radius, dist)); + /*--- Evaluation of Radial Basis Function ---*/ + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(type, radius, dist)); - for( iDim = 0; iDim < nDim; iDim++){ - localError[iDim] += rbf*coefficients[cNode + iDim*Global_nControlNodes]; + /*--- Add contribution to error ---*/ + for(auto iDim = 0u; iDim < nDim; iDim++){ + localError[iDim] += rbf*InterpCoeff[jNode*nDim + iDim]; } } - // cout << boundaryNodes[iNode]->GetIndex() << '\t' << localError[0] << '\t' << localError[1] << endl; - return localError; } -void CRadialBasisFunctionInterpolation::SetCorrection(CGeometry* geometry){ - unsigned long iVertex, iNode, iDim, i, j, pointID; - unsigned long nVertexBound = nBoundaryNodes; - su2double dist; +void CRadialBasisFunctionInterpolation::SetCorrection(CGeometry* geometry, CConfig* config, const RADIAL_BASIS& type, const vector& internalNodes){ + + /*--- The non-selected control nodes still have a nonzero error once the maximum error falls below the data reduction tolerance. + This error is applied as correction and interpolated into the volumetric mesh for internal nodes that fall within the correction radius. + To evaluate whether an internal node falls within the correction radius an AD tree is constructed of the boundary nodes, + making it possible to determine the distance to the nearest boundary node. ---*/ + + /*--- Construction of the AD tree consisting of the non-selected boundary nodes ---*/ + + /*--- Number of non-selected boundary nodes ---*/ + const unsigned long nVertexBound = BoundNodes.size(); + + /*--- Vector storing the coordinates of the boundary nodes ---*/ vector Coord_bound(nDim*nVertexBound); + + /*--- Vector storing the IDs of the boundary nodes ---*/ vector PointIDs(nVertexBound); - int rankID; - su2double CorrectionRadius = GreedyCorrectionFactor*MaxError; - i = 0; - j = 0; - for(iVertex = 0; iVertex < nVertexBound; iVertex++){ - iNode = boundaryNodes[iVertex]->GetIndex(); + /*--- Correction Radius, equal to maximum error times a prescribed constant ---*/ + const su2double CorrectionRadius = config->GetRBF_DataRedCorrectionFactor()*MaxErrorGlobal; + + /*--- Storing boundary node information ---*/ + unsigned long i = 0; + unsigned long j = 0; + for(auto iVertex = 0ul; iVertex < nVertexBound; iVertex++){ + auto iNode = BoundNodes[iVertex]->GetIndex(); PointIDs[i++] = iVertex; - for(iDim = 0; iDim < nDim; iDim++){ + for(auto iDim = 0u; iDim < nDim; iDim++){ Coord_bound[j++] = geometry->nodes->GetCoord(iNode, iDim); } } + /*--- Construction of AD tree ---*/ CADTPointsOnlyClass BoundADT(nDim, nVertexBound, Coord_bound.data(), PointIDs.data(), true); - for(iNode = 0; iNode < nInternalNodes; iNode++){ + /*--- ID of nearest boundary node ---*/ + unsigned long pointID; + /*--- Distance to nearest boundary node ---*/ + su2double dist; + /*--- rank of nearest boundary node ---*/ + int rankID; + + /*--- Interpolation of the correction to the internal nodes that fall within the correction radius ---*/ + for(auto iNode = 0ul; iNode < internalNodes.size(); iNode++){ + + /*--- Find nearest node ---*/ BoundADT.DetermineNearestNode(geometry->nodes->GetCoord(internalNodes[iNode]), dist, pointID, rankID); - auto err = boundaryNodes[pointID]->GetError(); - auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(kindRBF, CorrectionRadius, dist)); - for(iDim = 0; iDim < nDim; iDim++){ + + /*--- Get error of nearest node ---*/ + auto err = BoundNodes[pointID]->GetError(); + + /*--- evaluate RBF ---*/ + auto rbf = SU2_TYPE::GetValue(CRadialBasisFunction::Get_RadialBasisValue(type, CorrectionRadius, dist)); + + /*--- Apply correction to the internal node ---*/ + for(auto iDim = 0u; iDim < nDim; iDim++){ geometry->nodes->AddCoord(internalNodes[iNode], iDim, -rbf*err[iDim]); } } - for(iNode = 0; iNode < nBoundaryNodes; iNode++){ - auto err = boundaryNodes[iNode]->GetError(); - for(iDim = 0; iDim < nDim; iDim++){ - geometry->nodes->AddCoord(boundaryNodes[iNode]->GetIndex(), iDim, -err[iDim]); + /*--- Applying the correction to the non-selected boundary nodes ---*/ + for(auto iNode = 0ul; iNode < BoundNodes.size(); iNode++){ + auto err = BoundNodes[iNode]->GetError(); + for(auto iDim = 0u; iDim < nDim; iDim++){ + geometry->nodes->AddCoord(BoundNodes[iNode]->GetIndex(), iDim, -err[iDim]); } } +} + + +void CRadialBasisFunctionInterpolation::AddControlNode(unsigned long maxErrorNode){ + /*--- Addition of node to the reduced set of control nodes ---*/ + ReducedControlNodes.push_back(move(BoundNodes[maxErrorNode])); + + /*--- Removal of node among the non-selected boundary nodes ---*/ + BoundNodes.erase(BoundNodes.begin()+maxErrorNode); +} + + +void CRadialBasisFunctionInterpolation::Get_nCtrlNodesGlobal(){ + /*--- Determining the global number of control nodes ---*/ + + /*--- Local number of control nodes ---*/ + auto local_nControlNodes = ControlNodes->size(); + + /*--- Summation of local number of control nodes ---*/ + SU2_MPI::Allreduce(&local_nControlNodes, &nCtrlNodesGlobal, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); } \ No newline at end of file diff --git a/Common/src/grid_movement/CRadialBasisFunctionNode.cpp b/Common/src/grid_movement/CRadialBasisFunctionNode.cpp index f3bdea69046..4a00aae5ae4 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionNode.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionNode.cpp @@ -28,7 +28,12 @@ #include "../../include/grid_movement/CRadialBasisFunctionNode.hpp" CRadialBasisFunctionNode::CRadialBasisFunctionNode(unsigned long idx_val, unsigned short marker_val, unsigned long vertex_val){ + /*--- local node index ---*/ idx = idx_val; + + /*--- local marker index ---*/ marker_idx = marker_val; + + /*--- local vertex index ---*/ vertex_idx = vertex_val; }; \ No newline at end of file From 96d4fb63f1e4196d66e7eb2d8f16a499c7e06040 Mon Sep 17 00:00:00 2001 From: "F.A. van Steen" <48210335+FvanSteen@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:05:07 +0200 Subject: [PATCH 16/19] Update Common/include/CConfig.hpp MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Co-authored-by: Kürşat Yurt <57598663+kursatyurt@users.noreply.github.com> --- Common/include/CConfig.hpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index 44e10829ea6..8670796a3db 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -4402,7 +4402,7 @@ class CConfig { * \brief Get the type of mesh deformation method. * \return type of mesh deformation. */ - DEFORM_KIND GetDeform_Kind(void) const { return Deform_Kind; } + DEFORM_KIND GetDeform_Kind() const { return Deform_Kind; } /*! * \brief Determines use of data reduction methods for RBF mesh deformation. From ea3588013abfb5cf2004fcae546d83cffeab349d Mon Sep 17 00:00:00 2001 From: "F.A. van Steen" <48210335+FvanSteen@users.noreply.github.com> Date: Wed, 3 Jul 2024 22:37:12 +0200 Subject: [PATCH 17/19] Apply suggestions from code review MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Removal of void as input parameter and other minor changes Co-authored-by: Kürşat Yurt <57598663+kursatyurt@users.noreply.github.com> --- Common/include/grid_movement/CLinearElasticity.hpp | 2 +- Common/src/CConfig.cpp | 2 +- Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Common/include/grid_movement/CLinearElasticity.hpp b/Common/include/grid_movement/CLinearElasticity.hpp index b95f3a87797..e1745b06db2 100644 --- a/Common/include/grid_movement/CLinearElasticity.hpp +++ b/Common/include/grid_movement/CLinearElasticity.hpp @@ -66,7 +66,7 @@ class CLinearElasticity final: public CVolumetricMovement{ /*! * \brief Destructor of the class. */ - ~CLinearElasticity(void) override; + ~CLinearElasticity() override; /*! * \brief Grid deformation using the spring analogy method. diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 0d0fe6e5e71..742cec397f0 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -6478,7 +6478,7 @@ void CConfig::SetOutput(SU2_COMPONENT val_software, unsigned short val_izone) { if (val_software == SU2_COMPONENT::SU2_DEF) { cout << endl <<"---------------- Grid deformation parameters ( Zone " << iZone << " ) ----------------" << endl; - cout << "Grid deformation using a "; + cout << "Grid deformation using "; if (Deform_Kind == DEFORM_KIND::RBF){ cout << "Radial Basis Function interpolation method.\nRadial Basis Function: "; switch(Kind_RadialBasisFunction){ diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 898033bd405..5d5f67ce63c 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -33,7 +33,7 @@ CRadialBasisFunctionInterpolation::CRadialBasisFunctionInterpolation(CGeometry* geometry, CConfig* config) : CVolumetricMovement(geometry) {} -CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation(void) = default; +CRadialBasisFunctionInterpolation::~CRadialBasisFunctionInterpolation() = default; void CRadialBasisFunctionInterpolation::SetVolume_Deformation(CGeometry* geometry, CConfig* config, bool UpdateGeo, bool Derivative, bool ForwardProjectionDerivative){ From 2844510e3163d5aaa0968ce5a22cf9810fec6593 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Thu, 4 Jul 2024 10:14:33 +0200 Subject: [PATCH 18/19] Increased descreptiveness function names and small comment changes --- .../CRadialBasisFunctionInterpolation.hpp | 10 ++++++---- .../grid_movement/CVolumetricMovementFactory.hpp | 2 +- .../CRadialBasisFunctionInterpolation.cpp | 4 ++-- 3 files changed, 9 insertions(+), 7 deletions(-) diff --git a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp index 4d2e149e28a..daa99b5059d 100644 --- a/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp +++ b/Common/include/grid_movement/CRadialBasisFunctionInterpolation.hpp @@ -228,18 +228,20 @@ class CRadialBasisFunctionInterpolation : public CVolumetricMovement { /*! * \brief Custom comparison function, for sorting the CRadialBasisFunctionNode objects based on their index. * \param[in] a - First considered Radial Basis Function Node. - * \param[in] b - second considered Radial Basis Function Node. + * \param[in] b - Second considered Radial Basis Function Node. + * \return True if index of a is smaller than index of b. */ - inline static bool Compare(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ + inline static bool HasSmallerIndex(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ return a->GetIndex() < b->GetIndex(); } /*! * \brief Custom equality function, for obtaining a unique set of CRadialBasisFunctionNode objects. * \param[in] a - First considered Radial Basis Function Node. - * \param[in] b - second considered Radial Basis Function Node. + * \param[in] b - Second considered Radial Basis Function Node. + * \return True if index of a and b are equal. */ - inline static bool Equal(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ + inline static bool HasEqualIndex(CRadialBasisFunctionNode* a, CRadialBasisFunctionNode* b){ return a->GetIndex() == b->GetIndex(); } }; \ No newline at end of file diff --git a/Common/include/grid_movement/CVolumetricMovementFactory.hpp b/Common/include/grid_movement/CVolumetricMovementFactory.hpp index b917e57b57f..5ce673f1d58 100644 --- a/Common/include/grid_movement/CVolumetricMovementFactory.hpp +++ b/Common/include/grid_movement/CVolumetricMovementFactory.hpp @@ -35,7 +35,7 @@ namespace CVolumetricMovementFactory { * \brief Factory method for CVolumetricMovement objects. * \param[in] geometry_container - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. - * \return Pointer to volumetric moever on the heap, caller is responsible for deletion. + * \return Pointer to the allocated volumetric mover. */ CVolumetricMovement* CreateCVolumetricMovement(CGeometry* geometry, CConfig* config); diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index 898033bd405..c0c7fe3cbb5 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -198,10 +198,10 @@ void CRadialBasisFunctionInterpolation::SetBoundNodes(CGeometry* geometry, CConf } /*--- Sorting of the boundary nodes based on their index ---*/ - sort(BoundNodes.begin(), BoundNodes.end(), Compare); + sort(BoundNodes.begin(), BoundNodes.end(), HasSmallerIndex); /*--- Obtaining unique set ---*/ - BoundNodes.resize(std::distance(BoundNodes.begin(), unique(BoundNodes.begin(), BoundNodes.end(), Equal))); + BoundNodes.resize(std::distance(BoundNodes.begin(), unique(BoundNodes.begin(), BoundNodes.end(), HasEqualIndex))); } void CRadialBasisFunctionInterpolation::SetCtrlNodes(CConfig* config){ From 740efab6ec455144daaa128d2b61f3c5cbc43680 Mon Sep 17 00:00:00 2001 From: FvanSteen Date: Mon, 15 Jul 2024 15:24:36 +0200 Subject: [PATCH 19/19] Added consideration for markers considered as internal nodes --- .../CRadialBasisFunctionInterpolation.cpp | 24 ++++++++++++++++++- 1 file changed, 23 insertions(+), 1 deletion(-) diff --git a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp index df1c557a99f..6ec015b6e27 100644 --- a/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp +++ b/Common/src/grid_movement/CRadialBasisFunctionInterpolation.cpp @@ -331,6 +331,28 @@ void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CC } } + /*--- Adding nodes on markers considered as internal nodes ---*/ + for (auto iMarker = 0u; iMarker < geometry->GetnMarker(); iMarker++){ + + /*--- Check if marker is considered as internal nodes ---*/ + if(config->GetMarker_All_Deform_Mesh_Internal(iMarker)){ + + /*--- Loop over marker vertices ---*/ + for (auto iVertex = 0ul; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + /*--- Local node index ---*/ + auto iNode = geometry->vertex[iMarker][iVertex]->GetNode(); + + /*--- if not among the boundary nodes ---*/ + if (find_if (BoundNodes.begin(), BoundNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == iNode;}) == BoundNodes.end()) { + internalNodes.push_back(iNode); + } + } + } + } + + + /*--- In case of a parallel computation, the nodes on the send/receive markers are included as internal nodes if they are not already a boundary node with known deformation ---*/ @@ -347,7 +369,7 @@ void CRadialBasisFunctionInterpolation::SetInternalNodes(CGeometry* geometry, CC /*--- Local node index ---*/ auto iNode = geometry->vertex[iMarker][iVertex]->GetNode(); - // /*--- if not among the boundary nodes ---*/ + /*--- if not among the boundary nodes ---*/ if (find_if (BoundNodes.begin(), BoundNodes.end(), [&](CRadialBasisFunctionNode* i){return i->GetIndex() == iNode;}) == BoundNodes.end()) { internalNodes.push_back(iNode); }