diff --git a/Common/include/CConfig.hpp b/Common/include/CConfig.hpp index c8a9819435f..87291feba80 100644 --- a/Common/include/CConfig.hpp +++ b/Common/include/CConfig.hpp @@ -676,7 +676,7 @@ class CConfig { unsigned short nConfig_Files; /*!< \brief Number of config files for multiphysics problems. */ string *Config_Filenames; /*!< \brief List of names for configuration files. */ - unsigned short *Kind_WallFunctions; /*!< \brief The kind of wall function to use for the corresponding markers. */ + WALL_FUNCTIONS *Kind_WallFunctions; /*!< \brief The kind of wall function to use for the corresponding markers. */ unsigned short **IntInfo_WallFunctions; /*!< \brief Additional integer information for the wall function markers. */ su2double **DoubleInfo_WallFunctions; /*!< \brief Additional double information for the wall function markers. */ unsigned short *Marker_All_Monitoring, /*!< \brief Global index for monitoring using the grid information. */ @@ -816,21 +816,23 @@ class CConfig { Turb2LamViscRatio_FreeStream, /*!< \brief Ratio of turbulent to laminar viscosity. */ NuFactor_FreeStream, /*!< \brief Ratio of turbulent to laminar viscosity. */ NuFactor_Engine, /*!< \brief Ratio of turbulent to laminar viscosity at the engine. */ - SecondaryFlow_ActDisk, /*!< \brief Ratio of turbulent to laminar viscosity at the actuator disk. */ - Initial_BCThrust, /*!< \brief Ratio of turbulent to laminar viscosity at the actuator disk. */ - Pressure_FreeStream, /*!< \brief Total pressure of the fluid. */ - Pressure_Thermodynamic, /*!< \brief Thermodynamic pressure of the fluid. */ - Temperature_FreeStream, /*!< \brief Total temperature of the fluid. */ - Temperature_ve_FreeStream; /*!< \brief Total vibrational-electronic temperature of the fluid. */ - su2double Prandtl_Lam, /*!< \brief Laminar Prandtl number for the gas. */ - Prandtl_Turb, /*!< \brief Turbulent Prandtl number for the gas. */ - Length_Ref, /*!< \brief Reference length for non-dimensionalization. */ - Pressure_Ref, /*!< \brief Reference pressure for non-dimensionalization. */ - Temperature_Ref, /*!< \brief Reference temperature for non-dimensionalization.*/ - Temperature_ve_Ref, /*!< \brief Reference vibrational-electronic temperature for non-dimensionalization.*/ - Density_Ref, /*!< \brief Reference density for non-dimensionalization.*/ - Velocity_Ref, /*!< \brief Reference velocity for non-dimensionalization.*/ - Time_Ref, /*!< \brief Reference time for non-dimensionalization. */ + SecondaryFlow_ActDisk, /*!< \brief Ratio of turbulent to laminar viscosity at the actuator disk. */ + Initial_BCThrust, /*!< \brief Ratio of turbulent to laminar viscosity at the actuator disk. */ + Pressure_FreeStream, /*!< \brief Total pressure of the fluid. */ + Pressure_Thermodynamic, /*!< \brief Thermodynamic pressure of the fluid. */ + Temperature_FreeStream, /*!< \brief Total temperature of the fluid. */ + Temperature_ve_FreeStream; /*!< \brief Total vibrational-electronic temperature of the fluid. */ + su2double Prandtl_Lam, /*!< \brief Laminar Prandtl number for the gas. */ + Prandtl_Turb, /*!< \brief Turbulent Prandtl number for the gas. */ + wallModelKappa, /*!< \brief von Karman constant kappa for turbulence wall modeling */ + wallModelB, /*!< \brief constant B for turbulence wall modeling */ + Length_Ref, /*!< \brief Reference length for non-dimensionalization. */ + Pressure_Ref, /*!< \brief Reference pressure for non-dimensionalization. */ + Temperature_Ref, /*!< \brief Reference temperature for non-dimensionalization.*/ + Temperature_ve_Ref, /*!< \brief Reference vibrational-electronic temperature for non-dimensionalization.*/ + Density_Ref, /*!< \brief Reference density for non-dimensionalization.*/ + Velocity_Ref, /*!< \brief Reference velocity for non-dimensionalization.*/ + Time_Ref, /*!< \brief Reference time for non-dimensionalization. */ Viscosity_Ref, /*!< \brief Reference viscosity for non-dimensionalization. */ Conductivity_Ref, /*!< \brief Reference conductivity for non-dimensionalization. */ Energy_Ref, /*!< \brief Reference viscosity for non-dimensionalization. */ @@ -1255,7 +1257,7 @@ class CConfig { su2double** & ActDisk_PressJump, su2double** & ActDisk_TempJump, su2double** & ActDisk_Omega); void addWallFunctionOption(const string &name, unsigned short &list_size, - string* &string_field, unsigned short* &val_Kind_WF, + string* &string_field, WALL_FUNCTIONS* &val_Kind_WF, unsigned short** &val_IntInfo_WF, su2double** &val_DoubleInfo_WF); void addPythonOption(const string name); @@ -1664,6 +1666,18 @@ class CConfig { */ su2double GetPrandtl_Turb(void) const { return Prandtl_Turb; } + /*! + * \brief Get the value of the von Karman constant kappa for turbulence wall modeling. + * \return von Karman constant. + */ + su2double GetwallModelKappa(void) const { return wallModelKappa; } + + /*! + * \brief Get the value of the von Karman constant kappa for turbulence wall modeling. + * \return von Karman constant. + */ + su2double GetwallModelB(void) const { return wallModelB; } + /*! * \brief Get the value of the thermal conductivity for solids. * \return Thermal conductivity (solid). @@ -5235,7 +5249,7 @@ class CConfig { * \param[in] ext - the extension to be added. * \return The new filename */ - string GetFilename(string filename, string ext, unsigned long Iter) const; + string GetFilename(string filename, string ext, int Iter) const; /*! * \brief Append the zone index to the restart or the solution files. @@ -5444,7 +5458,8 @@ class CConfig { * \param[in] val_val - Value of the design variable that we want to read. * \return Design variable step. */ - su2double GetDV_Value(unsigned short val_dv, unsigned short val_val = 0) const { return DV_Value[val_dv][val_val]; } + su2double& GetDV_Value(unsigned short val_dv, unsigned short val_val = 0) { return DV_Value[val_dv][val_val]; } + const su2double& GetDV_Value(unsigned short val_dv, unsigned short val_val = 0) const { return DV_Value[val_dv][val_val]; } /*! * \brief Set the value of the design variable step, we use this value in design problems. @@ -6617,7 +6632,7 @@ class CConfig { * \param[in] val_marker - String of the viscous wall marker. * \return The type of wall function treatment. */ - unsigned short GetWallFunction_Treatment(string val_marker) const; + WALL_FUNCTIONS GetWallFunction_Treatment(string val_marker) const; /*! * \brief Get the additional integer info for the wall function treatment diff --git a/Common/include/basic_types/ad_structure.hpp b/Common/include/basic_types/ad_structure.hpp index 620da3246f5..18c430c7b2f 100644 --- a/Common/include/basic_types/ad_structure.hpp +++ b/Common/include/basic_types/ad_structure.hpp @@ -271,14 +271,6 @@ namespace AD{ extern ExtFuncHelper* FuncHelper; - /*--- Stores the indices of the input variables (they might be overwritten) ---*/ - - extern std::vector inputValues; - - /*--- Current position inside the adjoint vector ---*/ - - extern int adjointVectorPosition; - extern bool Status; extern bool PreaccActive; @@ -297,28 +289,17 @@ namespace AD{ extern std::vector TapePositions; - extern std::vector localInputValues; - - extern std::vector localOutputValues; - extern codi::PreaccumulationHelper PreaccHelper; /*--- Reference to the tape. ---*/ - FORCEINLINE su2double::TapeType& getGlobalTape() { - return su2double::getGlobalTape(); - } + FORCEINLINE su2double::TapeType& getGlobalTape() {return su2double::getGlobalTape();} - FORCEINLINE void RegisterInput(su2double &data, bool push_index = true) { - AD::getGlobalTape().registerInput(data); - if (push_index) { - inputValues.push_back(data.getGradientData()); - } - } + FORCEINLINE void RegisterInput(su2double &data) {AD::getGlobalTape().registerInput(data);} FORCEINLINE void RegisterOutput(su2double& data) {AD::getGlobalTape().registerOutput(data);} - FORCEINLINE void ResetInput(su2double &data) {data.getGradientData() = su2double::GradientData();} + FORCEINLINE void ResetInput(su2double &data) {data = data.getValue();} FORCEINLINE void StartRecording() {AD::getGlobalTape().setActive();} @@ -335,7 +316,6 @@ namespace AD{ opdi::logic->prepareEvaluate(); #endif AD::getGlobalTape().evaluate(); - adjointVectorPosition = 0; } FORCEINLINE void ComputeAdjoint(unsigned short enter, unsigned short leave) { @@ -346,8 +326,6 @@ namespace AD{ #else AD::getGlobalTape().evaluate(TapePositions[enter], TapePositions[leave]); #endif - if (leave == 0) - adjointVectorPosition = 0; } FORCEINLINE void Reset() { @@ -355,10 +333,6 @@ namespace AD{ #if defined(HAVE_OPDI) opdi::logic->reset(); #endif - if (inputValues.size() != 0) { - adjointVectorPosition = 0; - inputValues.clear(); - } if (TapePositions.size() != 0) { #if defined(HAVE_OPDI) for (TapePosition& pos : TapePositions) { diff --git a/Common/include/basic_types/datatype_structure.hpp b/Common/include/basic_types/datatype_structure.hpp index 039df331200..b30d81555f1 100644 --- a/Common/include/basic_types/datatype_structure.hpp +++ b/Common/include/basic_types/datatype_structure.hpp @@ -95,19 +95,9 @@ namespace SU2_TYPE { FORCEINLINE void SetDerivative(su2double& data, const passivedouble &val) {data.setGradient(val);} -#ifdef CODI_REVERSE_TYPE - FORCEINLINE passivedouble GetSecondary(const su2double& data) { - return AD::getGlobalTape().getGradient(AD::inputValues[AD::adjointVectorPosition++]); - } - - FORCEINLINE passivedouble GetDerivative(const su2double& data) { - return AD::getGlobalTape().getGradient(AD::inputValues[AD::adjointVectorPosition++]); - } -#else // forward FORCEINLINE passivedouble GetSecondary(const su2double& data) {return data.getGradient();} FORCEINLINE passivedouble GetDerivative(const su2double& data) {return data.getGradient();} -#endif #else // passive type, no AD diff --git a/Common/include/code_config.hpp b/Common/include/code_config.hpp index 377432ee945..c1600b310f4 100644 --- a/Common/include/code_config.hpp +++ b/Common/include/code_config.hpp @@ -60,6 +60,13 @@ template using su2enable_if = typename std::enable_if::type; +/*--- Compile-time type selection. ---*/ +template struct su2conditional { using type = T; }; +template struct su2conditional { using type = F; }; + +template +using su2conditional_t = typename su2conditional::type; + /*--- Detect compilation with OpenMP. ---*/ #if defined(_OPENMP) #define HAVE_OMP @@ -103,7 +110,7 @@ using su2double = codi::RealForward; using su2double = double; #endif -/*--- This type can be used for (rare) compatiblity cases or for +/*--- This type can be used for (rare) compatibility cases or for * computations that are intended to be (always) passive. ---*/ using passivedouble = double; @@ -116,9 +123,13 @@ using su2mixedfloat = passivedouble; /*--- Detect if OpDiLib has to be used. ---*/ #if defined(HAVE_OMP) && defined(CODI_REVERSE_TYPE) +#ifndef __INTEL_COMPILER #define HAVE_OPDI +#else +#warning Hybrid parallel reverse mode AD cannot be used with Intel compilers. #endif #if (_OPENMP >= 201811 && !defined(FORCE_OPDI_MACRO_BACKEND)) || defined(FORCE_OPDI_OMPT_BACKEND) #define HAVE_OMPT #endif +#endif diff --git a/Common/include/fem/fem_geometry_structure.hpp b/Common/include/fem/fem_geometry_structure.hpp index fb4787d645c..eec7e3bac29 100644 --- a/Common/include/fem/fem_geometry_structure.hpp +++ b/Common/include/fem/fem_geometry_structure.hpp @@ -1227,11 +1227,14 @@ class CMeshFEM_DG: public CMeshFEM { void SetWallDistance(su2double val) override; /*! - * \brief Set the wall distance based on an previously constructed ADT - * \param[in] config - Definition of the particular problem. - * \param[in] WallADT - The ADT to compute the wall distance + * \brief Reduce the wall distance based on an previously constructed ADT. + * \details The ADT might belong to another zone, giving rise to lower wall distances + * than those already stored. + * \param[in] WallADT - The ADT to reduce the wall distance + * \param[in] config - Config of this geometry (not the ADT zone's geometry) + * \param[in] iZone - ignored */ - void SetWallDistance(const CConfig *config, CADTElemClass* WallADT) override; + void SetWallDistance(CADTElemClass* WallADT, const CConfig* config, unsigned short iZone) override; }; /*! diff --git a/Common/include/geometry/CGeometry.hpp b/Common/include/geometry/CGeometry.hpp index cc8aa2867b2..bdde61d4290 100644 --- a/Common/include/geometry/CGeometry.hpp +++ b/Common/include/geometry/CGeometry.hpp @@ -1234,14 +1234,14 @@ class CGeometry { * \brief Ray Intersects Triangle (Moller and Trumbore algorithm) */ bool RayIntersectsTriangle(const su2double orig[3], const su2double dir[3], - const su2double vert0[3], const su2double vert1[3], const su2double vert2[3], - su2double *intersect); + const su2double vert0[3], const su2double vert1[3], const su2double vert2[3], + su2double *intersect); /*! * \brief Segment Intersects Triangle */ bool SegmentIntersectsTriangle(su2double point0[3], const su2double point1[3], - su2double vert0[3], su2double vert1[3], su2double vert2[3]); + su2double vert0[3], su2double vert1[3], su2double vert2[3]); /*! * \brief Segment Intersects Line (for 2D FFD Intersection) @@ -1250,16 +1250,15 @@ class CGeometry { /*! * \brief Register the coordinates of the mesh nodes. - * \param[in] config */ - void RegisterCoordinates(const CConfig *config) const; + void RegisterCoordinates() const; /*! * \brief Update the multi-grid structure and the wall-distance. * \param geometry_container - Geometrical definition. * \param config - Config */ - void UpdateGeometry(CGeometry **geometry_container, CConfig *config); + static void UpdateGeometry(CGeometry **geometry_container, CConfig *config); /*! * \brief Update the multi-grid structure for the customized boundary conditions @@ -1683,11 +1682,14 @@ class CGeometry { virtual std::unique_ptr ComputeViscousWallADT(const CConfig *config) const { return nullptr; } /*! - * \brief Set the wall distance based on an previously constructed ADT - * \param[in] config - Definition of the particular problem. - * \param[in] WallADT - The ADT to compute the wall distance + * \brief Reduce the wall distance based on an previously constructed ADT. + * \details The ADT might belong to another zone, giving rise to lower wall distances + * than those already stored. + * \param[in] WallADT - The ADT to reduce the wall distance + * \param[in] config - Config of this geometry (not the ADT zone's geometry) + * \param[in] iZone - Zone whose markers made the ADT */ - virtual void SetWallDistance(const CConfig *config, CADTElemClass* WallADT) {} + virtual void SetWallDistance(CADTElemClass* WallADT, const CConfig* config, unsigned short iZone = numeric_limits::max()) {} /*! * \brief Set wall distances a specific value diff --git a/Common/include/geometry/CPhysicalGeometry.hpp b/Common/include/geometry/CPhysicalGeometry.hpp index 4f8866adca3..21e1ec02b7f 100644 --- a/Common/include/geometry/CPhysicalGeometry.hpp +++ b/Common/include/geometry/CPhysicalGeometry.hpp @@ -104,9 +104,6 @@ class CPhysicalGeometry final : public CGeometry { unsigned long *Elem_ID_BoundTria_Linear{nullptr}; unsigned long *Elem_ID_BoundQuad_Linear{nullptr}; - vector GlobalMarkerStorageDispl; - vector GlobalRoughness_Height; - su2double Streamwise_Periodic_RefNode[MAXNDIM] = {0}; /*!< \brief Coordinates of the reference node [m] on the receiving periodic marker, for recovered pressure/temperature computation only.*/ public: @@ -767,10 +764,14 @@ class CPhysicalGeometry final : public CGeometry { std::unique_ptr ComputeViscousWallADT(const CConfig *config) const override; /*! - * \brief Set the wall distance based on an previously constructed ADT - * \param[in] WallADT - The ADT to compute the wall distance + * \brief Reduce the wall distance based on an previously constructed ADT. + * \details The ADT might belong to another zone, giving rise to lower wall distances + * than those already stored. + * \param[in] WallADT - The ADT to reduce the wall distance + * \param[in] config - ignored + * \param[in] iZone - zone whose markers made the ADT */ - void SetWallDistance(const CConfig *config, CADTElemClass* WallADT) override; + void SetWallDistance(CADTElemClass* WallADT, const CConfig* config, unsigned short iZone) override; /*! * \brief Set wall distances a specific value @@ -781,11 +782,6 @@ class CPhysicalGeometry final : public CGeometry { } } - /*! - * \brief Set roughness values for markers in a global array. - */ - void SetGlobalMarkerRoughness(const CConfig* config); - /*! * \brief For streamwise periodicity, find & store a unique reference node on the designated periodic inlet. * \param[in] config - Definition of the particular problem. diff --git a/Common/include/geometry/dual_grid/CPoint.hpp b/Common/include/geometry/dual_grid/CPoint.hpp index 9db963524ad..487b0836292 100644 --- a/Common/include/geometry/dual_grid/CPoint.hpp +++ b/Common/include/geometry/dual_grid/CPoint.hpp @@ -32,6 +32,7 @@ #include "../../containers/container_decorators.hpp" #include "../../toolboxes/graph_toolbox.hpp" #include +#include "../../toolboxes/ndflattener.hpp" using namespace std; @@ -60,6 +61,9 @@ class CPoint { su2activevector Volume; /*!< \brief Volume or Area of the control volume in 3D and 2D. */ su2activevector Volume_n; /*!< \brief Volume at time n. */ su2activevector Volume_nM1; /*!< \brief Volume at time n-1. */ + su2activevector Volume_Old; /*!< \brief Old containers for Volume. */ + su2activevector Volume_n_Old; /*!< \brief Old containers for Volume at time n. */ + su2activevector Volume_nM1_Old; /*!< \brief Old containers for Volume at time n-1. */ su2activevector Periodic_Volume; /*!< \brief Missing component of volume or area of a control volume on a periodic marker in 3D and 2D. */ su2vector Domain; /*!< \brief Indicates if a point must be computed or belong to another boundary */ @@ -85,7 +89,14 @@ class CPoint { su2vector Agglomerate; /*!< \brief This flag indicates if the element has been agglomerated. */ su2vector nNeighbor; /*!< \brief Number of neighbors, needed by some numerical methods. */ + + /*--- Closest element on a viscous wall, and distance to it. ---*/ su2activevector Wall_Distance; /*!< \brief Distance to the nearest wall. */ + su2vector ClosestWall_Rank; /*!< \brief Rank of process holding the closest wall element. */ + su2vector ClosestWall_Zone; /*!< \brief Zone index of closest wall element. */ + su2vector ClosestWall_Marker; /*!< \brief Marker index of closest wall element, for given rank and zone index. */ + su2vector ClosestWall_Elem; /*!< \brief Element index of closest wall element, for givenrank, zone and marker index. */ + su2activevector SharpEdge_Distance; /*!< \brief Distance to a sharp edge. */ su2activevector Curvature; /*!< \brief Value of the surface curvature (SU2_GEO). */ su2activevector MaxLength; /*!< \brief The maximum cell-center to cell-center length. */ @@ -415,7 +426,19 @@ class CPoint { * \brief Set the value of the distance to the nearest wall. * \param[in] iPoint - Index of the point. * \param[in] distance - Value of the distance. - */ + * \param[in] rankID - Rank of process holding the closest wall element. + * \param[in] zoneID - Zone index of closest wall element. + * \param[in] markerID - Marker index of closest wall element. + * \param[in] elemID - Element index of closest wall element. + */ + inline void SetWall_Distance(unsigned long iPoint, su2double distance, int rankID, unsigned short zoneID, + unsigned short markerID, unsigned long elemID) { + Wall_Distance(iPoint) = distance; + ClosestWall_Rank(iPoint) = rankID; + ClosestWall_Zone(iPoint) = zoneID; + ClosestWall_Marker(iPoint) = markerID; + ClosestWall_Elem(iPoint) = elemID; + } inline void SetWall_Distance(unsigned long iPoint, su2double distance) { Wall_Distance(iPoint) = distance; } /*! @@ -540,10 +563,35 @@ class CPoint { void SetVolume_n(); /*! - * \brief Set the volume of the control volume at time n+1. + * \brief Set the volume of the control volume at time n-1. */ void SetVolume_nM1(); + /*! + * \brief Set the volume of the control volume at time n using n-1. + */ + void SetVolume_n_from_OldnM1(); + + /*! + * \brief Set the volume of the control volume at current time using time n. + */ + void SetVolume_from_Oldn(); + + /*! + * \brief Set the Volume to Volume_Old. + */ + void SetVolume_Old(); + + /*! + * \brief Set the Volume_n to Volume_n_Old. + */ + void SetVolume_n_Old(); + + /*! + * \brief Set the Volume_nM1 to Volume_nM1_Old. + */ + void SetVolume_nM1_Old(); + /*! * \brief Set the parent control volume of an agglomerated control volume. * \param[in] iPoint - Index of the point. @@ -783,50 +831,37 @@ class CPoint { } /*! - * \brief Set the adjoint values of the coordinates. + * \brief Register coordinates of a point. * \param[in] iPoint - Index of the point. - * \param[in] adj_sol - The adjoint values of the coordinates. + * \param[in] input - Register as input or output. */ - inline void SetAdjointCoord(unsigned long iPoint, const su2double *adj_coor) { - for (unsigned long iDim = 0; iDim < nDim; iDim++) - SU2_TYPE::SetDerivative(Coord(iPoint,iDim), SU2_TYPE::GetValue(adj_coor[iDim])); + inline void RegisterCoordinates(unsigned long iPoint, bool input) { + for (unsigned long iDim = 0; iDim < nDim; iDim++) { + if(input) { + AD::RegisterInput(Coord(iPoint,iDim)); + AD::SetIndex(AD_InputIndex(iPoint,iDim), Coord(iPoint,iDim)); + } + else { + AD::RegisterOutput(Coord(iPoint,iDim)); + AD::SetIndex(AD_OutputIndex(iPoint,iDim), Coord(iPoint,iDim)); + } + } } /*! - * \brief Set the adjoint values of the coordinates. - * \param[in] iPoint - Index of the point. - * \param[in] adj_sol - The adjoint values of the coordinates. - */ - inline void SetAdjointCoord_LocalIndex(unsigned long iPoint, const su2double *adj_coor) { - for (unsigned long iDim = 0; iDim < nDim; iDim++) - AD::SetDerivative(AD_OutputIndex(iPoint,iDim), SU2_TYPE::GetValue(adj_coor[iDim])); - } - - /*! - * \brief Get the adjoint values of the coordinates. - * \param[in] iPoint - Index of the point. - * \param[in] adj_sol - The adjoint values of the coordinates. - */ - inline void GetAdjointCoord(unsigned long iPoint, su2double *adj_coor) const { - for (unsigned long iDim = 0; iDim < nDim; iDim++) - adj_coor[iDim] = SU2_TYPE::GetDerivative(Coord(iPoint,iDim)); - } - - /*! - * \brief Get the adjoint values of the coordinates. - * \param[in] iPoint - Index of the point. - * \param[in] adj_sol - The adjoint values of the coordinates. + * \brief Set wall roughnesses according to stored closest wall information. + * \param[in] roughness - Mapping [rank][zone][marker] -> roughness */ - inline void GetAdjointCoord_LocalIndex(unsigned long iPoint, su2double *adj_coor) const { - for (unsigned long iDim = 0; iDim < nDim; iDim++) - adj_coor[iDim] = AD::GetDerivative(AD_InputIndex(iPoint,iDim)); + template + void SetWallRoughness(Roughness_type const& roughness){ + for (unsigned long iPoint=0; iPoint= 0){ + SetRoughnessHeight(iPoint, roughness[rankID][zoneID][markerID]); + } + } } - /*! - * \brief Set the adjoint vector indices of Coord vector. - * \param[in] iPoint - Index of the point. - * \param[in] input - Save them to the input or output indices vector. - */ - void SetIndex(unsigned long iPoint, bool input); - }; diff --git a/Common/include/geometry/primal_grid/CPrimalGrid.hpp b/Common/include/geometry/primal_grid/CPrimalGrid.hpp index e5b7f19ca50..7096aa08f09 100644 --- a/Common/include/geometry/primal_grid/CPrimalGrid.hpp +++ b/Common/include/geometry/primal_grid/CPrimalGrid.hpp @@ -34,6 +34,7 @@ #include #include #include +#include #include "../../CConfig.hpp" diff --git a/Common/include/linear_algebra/CSysMatrix.hpp b/Common/include/linear_algebra/CSysMatrix.hpp index 75ab1a052c3..8d32302ee84 100644 --- a/Common/include/linear_algebra/CSysMatrix.hpp +++ b/Common/include/linear_algebra/CSysMatrix.hpp @@ -36,8 +36,6 @@ #include #include -using namespace std; - /*--- In forward mode the matrix is not of a built-in type. ---*/ #if defined(HAVE_MKL) && !defined(CODI_FORWARD_TYPE) #include "mkl.h" diff --git a/Common/include/option_structure.hpp b/Common/include/option_structure.hpp index 0a548762a37..f5d6a61a972 100644 --- a/Common/include/option_structure.hpp +++ b/Common/include/option_structure.hpp @@ -935,23 +935,23 @@ static const MapType RoeLowDiss_Map = { /*! * \brief Types of wall functions. */ -enum ENUM_WALL_FUNCTIONS { - NO_WALL_FUNCTION = 0, /*!< \brief No wall function treatment, integration to the wall. Default behavior. */ - STANDARD_WALL_FUNCTION = 1, /*!< \brief Standard wall function. */ - ADAPTIVE_WALL_FUNCTION = 2, /*!< \brief Adaptive wall function. Formulation depends on y+. */ - SCALABLE_WALL_FUNCTION = 3, /*!< \brief Scalable wall function. */ - EQUILIBRIUM_WALL_MODEL = 4, /*!< \brief Equilibrium wall model for LES. */ - NONEQUILIBRIUM_WALL_MODEL = 5, /*!< \brief Non-equilibrium wall model for LES. */ - LOGARITHMIC_WALL_MODEL = 6 /*!< \brief Logarithmic law-of-the-wall model for LES. */ -}; -static const MapType Wall_Functions_Map = { - MakePair("NO_WALL_FUNCTION", NO_WALL_FUNCTION) - MakePair("STANDARD_WALL_FUNCTION", STANDARD_WALL_FUNCTION) - MakePair("ADAPTIVE_WALL_FUNCTION", ADAPTIVE_WALL_FUNCTION) - MakePair("SCALABLE_WALL_FUNCTION", SCALABLE_WALL_FUNCTION) - MakePair("EQUILIBRIUM_WALL_MODEL", EQUILIBRIUM_WALL_MODEL) - MakePair("NONEQUILIBRIUM_WALL_MODEL", NONEQUILIBRIUM_WALL_MODEL) - MakePair("LOGARITHMIC_WALL_MODEL", LOGARITHMIC_WALL_MODEL) +enum class WALL_FUNCTIONS { + NONE , /*!< \brief No wall function treatment, integration to the wall. Default behavior. */ + STANDARD_FUNCTION , /*!< \brief Standard wall function. */ + ADAPTIVE_FUNCTION , /*!< \brief Adaptive wall function. Formulation depends on y+. */ + SCALABLE_FUNCTION , /*!< \brief Scalable wall function. */ + EQUILIBRIUM_MODEL , /*!< \brief Equilibrium wall model for LES. */ + NONEQUILIBRIUM_MODEL , /*!< \brief Non-equilibrium wall model for LES. */ + LOGARITHMIC_MODEL /*!< \brief Logarithmic law-of-the-wall model for LES. */ +}; +static const MapType Wall_Functions_Map = { + MakePair("NO_WALL_FUNCTION", WALL_FUNCTIONS::NONE) + MakePair("STANDARD_WALL_FUNCTION", WALL_FUNCTIONS::STANDARD_FUNCTION) + MakePair("ADAPTIVE_WALL_FUNCTION", WALL_FUNCTIONS::ADAPTIVE_FUNCTION) + MakePair("SCALABLE_WALL_FUNCTION", WALL_FUNCTIONS::SCALABLE_FUNCTION) + MakePair("EQUILIBRIUM_WALL_MODEL", WALL_FUNCTIONS::EQUILIBRIUM_MODEL) + MakePair("NONEQUILIBRIUM_WALL_MODEL", WALL_FUNCTIONS::NONEQUILIBRIUM_MODEL) + MakePair("LOGARITHMIC_WALL_MODEL", WALL_FUNCTIONS::LOGARITHMIC_MODEL) }; /*! diff --git a/Common/include/option_structure.inl b/Common/include/option_structure.inl index 94a59c664b0..cbcd4671bbf 100644 --- a/Common/include/option_structure.inl +++ b/Common/include/option_structure.inl @@ -1736,13 +1736,13 @@ class COptionWallFunction : public COptionBase { string name; // identifier for the option unsigned short &nMarkers; string* &markers; - unsigned short* &walltype; + WALL_FUNCTIONS* &walltype; unsigned short** &intInfo; su2double** &doubleInfo; public: COptionWallFunction(const string name, unsigned short &nMarker_WF, - string* &Marker_WF, unsigned short* &type_WF, + string* &Marker_WF, WALL_FUNCTIONS* &type_WF, unsigned short** &intInfo_WF, su2double** &doubleInfo_WF) : nMarkers(nMarker_WF), markers(Marker_WF), walltype(type_WF), intInfo(intInfo_WF), doubleInfo(doubleInfo_WF) { @@ -1774,14 +1774,16 @@ public: If not, create an error message and return. */ ++counter; const unsigned short indWallType = counter; - unsigned short typeWF = NO_WALL_FUNCTION; + auto typeWF = WALL_FUNCTIONS::NONE; bool validWF = true; if (counter == totalSize) validWF = false; else { - map::const_iterator it; + map::const_iterator it; it = Wall_Functions_Map.find(option_value[counter]); - if(it == Wall_Functions_Map.end()) validWF = false; - else typeWF = it->second; + if(it == Wall_Functions_Map.end()) + validWF = false; + else + typeWF = it->second; } if (!validWF ) { @@ -1801,9 +1803,9 @@ public: must be specified. Hence the counter must be updated accordingly. ---*/ switch( typeWF ) { - case EQUILIBRIUM_WALL_MODEL: counter += 3; break; - case NONEQUILIBRIUM_WALL_MODEL: counter += 2; break; - case LOGARITHMIC_WALL_MODEL: counter += 3; break; + case WALL_FUNCTIONS::EQUILIBRIUM_MODEL: counter += 3; break; + case WALL_FUNCTIONS::NONEQUILIBRIUM_MODEL: counter += 2; break; + case WALL_FUNCTIONS::LOGARITHMIC_MODEL: counter += 3; break; default: break; } @@ -1824,7 +1826,7 @@ public: /* Allocate the memory to store the data for the wall function markers. */ this->nMarkers = nVals; this->markers = new string[nVals]; - this->walltype = new unsigned short[nVals]; + this->walltype = new WALL_FUNCTIONS[nVals]; this->intInfo = new unsigned short*[nVals]; this->doubleInfo = new su2double*[nVals]; @@ -1843,7 +1845,7 @@ public: /* Determine the wall function type. As their validaties have already been tested, there is no need to do so again. */ - map::const_iterator it; + map::const_iterator it; it = Wall_Functions_Map.find(option_value[counter++]); this->walltype[i] = it->second; @@ -1852,7 +1854,7 @@ public: is needed, which is extracted from option_value. ---*/ switch( this->walltype[i] ) { - case EQUILIBRIUM_WALL_MODEL: { + case WALL_FUNCTIONS::EQUILIBRIUM_MODEL: { /* LES equilibrium wall model. The exchange distance, stretching factor and number of points in the wall model must be specified. */ @@ -1877,7 +1879,7 @@ public: break; } - case NONEQUILIBRIUM_WALL_MODEL: { + case WALL_FUNCTIONS::NONEQUILIBRIUM_MODEL: { /* LES non-equilibrium model. The RANS turbulence model and the exchange distance need to be specified. */ @@ -1910,7 +1912,7 @@ public: break; } - case LOGARITHMIC_WALL_MODEL: { + case WALL_FUNCTIONS::LOGARITHMIC_MODEL: { /* LES Logarithmic law-of-the-wall model. The exchange distance, stretching factor and number of points in the wall model must be specified. */ diff --git a/Common/include/parallelization/mpi_structure.cpp b/Common/include/parallelization/mpi_structure.cpp index 3f4b540211e..451d03178c5 100644 --- a/Common/include/parallelization/mpi_structure.cpp +++ b/Common/include/parallelization/mpi_structure.cpp @@ -123,41 +123,41 @@ void CBaseMPIWrapper::Error(std::string ErrorMsg, std::string FunctionName){ Abort(currentComm, 0); } -void CBaseMPIWrapper::CopyData(const void* sendbuf, void* recvbuf, int size, Datatype datatype) { +void CBaseMPIWrapper::CopyData(const void* sendbuf, void* recvbuf, int size, Datatype datatype, int recvshift, int sendshift) { switch (datatype) { case MPI_DOUBLE: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; case MPI_UNSIGNED_LONG: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; case MPI_LONG: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; case MPI_UNSIGNED_SHORT: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; case MPI_CHAR: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; case MPI_SHORT: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; case MPI_INT: for (int i = 0; i < size; i++) { - static_cast(recvbuf)[i] = static_cast(sendbuf)[i]; + static_cast(recvbuf)[i+recvshift] = static_cast(sendbuf)[i+sendshift]; } break; default: diff --git a/Common/include/parallelization/mpi_structure.hpp b/Common/include/parallelization/mpi_structure.hpp index 3ae5de48abd..a6d2524bb7f 100644 --- a/Common/include/parallelization/mpi_structure.hpp +++ b/Common/include/parallelization/mpi_structure.hpp @@ -503,7 +503,7 @@ class CBaseMPIWrapper { static int Rank, Size; static Comm currentComm; - static void CopyData(const void* sendbuf, void* recvbuf, int size, Datatype datatype); + static void CopyData(const void* sendbuf, void* recvbuf, int size, Datatype datatype, int recvshift=0, int sendshift=0); public: static void Error(std::string ErrorMsg, std::string FunctionName); @@ -570,7 +570,7 @@ class CBaseMPIWrapper { static inline void Allgatherv(const void* sendbuf, int sendcnt, Datatype sendtype, void* recvbuf, const int* recvcnt, const int* displs, Datatype recvtype, Comm comm) { - CopyData(sendbuf, recvbuf, sendcnt, sendtype); + CopyData(sendbuf, recvbuf, sendcnt, sendtype, displs[0]); } static inline void Allgather(const void* sendbuf, int sendcnt, Datatype sendtype, void* recvbuf, int recvcnt, @@ -596,7 +596,7 @@ class CBaseMPIWrapper { static inline void Alltoallv(const void* sendbuf, const int* sendcounts, const int* sdispls, Datatype sendtype, void* recvbuf, const int* recvcounts, const int* recvdispls, Datatype recvtype, Comm comm) { - CopyData(sendbuf, recvbuf, recvcounts[0], recvtype); + CopyData(sendbuf, recvbuf, recvcounts[0], recvtype, recvdispls[0], sdispls[0]); } static inline void Probe(int source, int tag, Comm comm, Status* status) {} diff --git a/Common/include/toolboxes/geometry_toolbox.hpp b/Common/include/toolboxes/geometry_toolbox.hpp index 458365fa3ee..8bd967f9b46 100644 --- a/Common/include/toolboxes/geometry_toolbox.hpp +++ b/Common/include/toolboxes/geometry_toolbox.hpp @@ -192,4 +192,17 @@ inline void Rotate(const Scalar R[][nDim], const Scalar* O, const Scalar* d, Sca } } +/*! \brief Tangent projection */ +template +inline void TangentProjection(Int nDim, const Mat& tensor, const Scalar* vector, Scalar* proj) { + + for (Int iDim = 0; iDim < nDim; iDim++) + proj[iDim] = DotProduct(nDim, tensor[iDim], vector); + + auto normalProj = DotProduct(nDim, proj, vector); + + for (Int iDim = 0; iDim < nDim; iDim++) + proj[iDim] -= normalProj * vector[iDim]; +} + } diff --git a/Common/include/toolboxes/ndflattener.hpp b/Common/include/toolboxes/ndflattener.hpp new file mode 100644 index 00000000000..8898c65e64a --- /dev/null +++ b/Common/include/toolboxes/ndflattener.hpp @@ -0,0 +1,828 @@ +/*! + * \file ndflattener.hpp + * \brief Flatten pointer-to-pointer-... arrays for MPI communication + * \author M. Aehle + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, SU2 Contributors (cf. AUTHORS.md) + * + * SU2 is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * SU2 is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with SU2. If not, see . + */ + +#pragma once + +#include +#include +#include +#include +#include + +#include "../containers/C2DContainer.hpp" +#include "../parallelization/mpi_structure.hpp" + +// --- Usage +/*! \page ndflattener_usage NdFlattener usage + * + * # What is an NdFlattener? + * + * NdFlattener is a container to store a deep copy of multidimensional data in a single object that provides a + * generic []...[] interface. The data and their structure are stored in few contiguous arrays, allowing for an + * efficient MPI gathering operation. + * + * # Which problem does it solve? + * In SU2, there is a lot of multidimensional data: data depending on K>1 indices, like a wall property + * depending on the rank, zone index, and marker index. + * + * The data is often stored non-contiguously as a "tree": + * - an array of pointers, each one of which points to + * - (repeat the previous line another (K-2) times) + * - an array of data. + * + * The individual arrays' sizes are usually unrelated to each other. Therefore in addition to this tree of + * pointers-to-...-to-data, usually there is a tree of pointers-to-...-to-size for each lower level. + * Instead of arrays, there might be getter functions for the data and the sizes. + * + * In order to use multidimensional data behind such a non-generic interface as an argument in a function call, + * we usually make the callee aware of the interface and expose all the trees: Either as separate pointers to arrays + * (or functions), which is tedious, or by handing an object in which they naturally live, which exposes much more + * information. + * + * If the callee is an MPI communication operation, this is not possible. Here, a frequent pattern is to copy the data + * into a single contiguous array, which is then communicated alongside with the structure (lengths of the arrays). + * + * The NdFlattener container is a systematic way to store multidimensional data in a single contiguous array, and + * the structure in few additional contiguous arrays. It exposes them through a generic []...[] interface and allows + * for an efficient MPI_Allgatherv-like operation. + * + * To demonstrate the usage of NdFlattener, let us store a property of type su2double that depends on + * the rank, zone index, and marker index. + * + * # Form the local NdFlattener + * by a "recursive function" like this: + * + * auto f_local = + * make_pair( nZone, [=](unsigned long iZone){ + * return make_pair( (Geometry of iZone)->GetnMarker() , [=](unsigned long iMarker){ + * return YOUR_PROPERTY(iZone, iMarker); + * }); + * }); + * NdFlattener<2> nd_local(f_local); + * + * It might be safer to explicitly capture what you need in the lambda expressions. + * + * You can also construct an NdFlattener without any arguments, and use NdFlattener::initialize(f_local). + * + * f_local is + * - a pair of an (exclusive) upper bound for the first index and a function that maps the first index to + * - a pair of an (exclusive) upper bound for the second index and a function that maps the second index to + * - (iterate this if there are more layers) + * - the value corresponding to these indices. + * The template parameter "2" is the number of indices. The data type (default: su2double) and the index type + * (default: unsigned long) are further optional template parameters. + * + * # Form the global NdFlattener + * by "collective communication" like this: + * + * NdFlattener<3> nd_global(Nd_MPI_Environment(), &nd_local); + * + * nd_global's first index is the rank, then the indices of nd_local follow. + * + * The struct Nd_MPI_Environment contains the relevant information about the parallel environment. The default + * values are suitable to communicate su2double data. In order to communicate data of another MPI datatype, + * use e.g. Nd_MPI_Environment(MPI_UNSIGNED_LONG). + * + * You can also construct an NdFlattener without any arguments, and use NdFlattener::initialize(mpi_env, &nd_local). + * + * # Refreshing + * If only the data but not the indices (i.e. the structure of sublists' lengths) have changed, you can refresh + * them with the call + * + * nd_local.refresh(f_local); // , or + * nd_global(Nd_MPI_Environment(), &nd_local); // respectively. + * + * An NdFlattener constructed or initialized from a "recursive function" or "collective communication" must be + * refreshed in the same way. + * + * We also provide a function NdFlattener::initialize_or_refresh, that initializes if not initialized, and refreshes + * otherwise. + * + * # Look-up + * You can access the NdFlattener via a "[]...[]" interface that resembles multidimensional arrays + * or pointer-to-pointer-... arrays. If you provide all of the K indices, this returns a reference + * to the data element. If you provide less than K indices, you obtain an IndexAccumulator object + * to which you can later pass more indices. With respect to the above example: + * + * std::cout << nd_global[rank][zone][marker]; // e.g. 4.0 + * auto nd_g_rank = nd_global[rank]; + * nd_g_rank[zone][marker] *= 2.0; + * std::cout << nd_g_rank[zone][marker]; // e.g. 8.0 + * + * You may use the IndexAccumulator repeatedly as long as the accessed NdFlattener exists. + * As NdFlatteners are always deep copies, the above block would not change nd_local or the non-contiguous + * data from which it was copied. + * + * Each index is checked to lie in the correct range dictated by the NdFlattener and the + * previous indices. You can obtain the minimal overflowing index with `size`: + * + * auto nd_g_rank = nd_global[rank]; + * std::cout << nd_g_rank[zone].size(); + * + * When all indices except the last one are fixed, the corresponding data is stored contiguously and a pointer + * to this 1D array can be retrieved by + * + * nd_global[rank][zone].data() + * + * # Constness + * The reference returned by the last `operator[]`, and the pointer returned by `data()`, are const if + * - the accessed NdFlattener object was const, or + * - one of the intermediate IndexAccumulator objects was qualified as const. + * + * This reflects the semantic meaning of const: + * + * NdFlattener<2> nd2(...); + * + * template set(T& t) { t[0] = 1.0; } + * set( nd2[0] ); // OK + * + * template set_const(T const& t) { t[0] = 1.0; } + * set_const( nd2[0] ); // does not compile + * + * # Unit tests + * The interface described here is tested in UnitTests/Common/toolboxes/ndflattener_tests.cpp, which may also + * serve as an addition example of how to use the NdFlattener. + */ + +// --- Implementation details--- +/*! \page ndflattener_implementationdetails Implementation details of NdFlattener + * If your array has K indices, instantiate this class with template parameter K, + * which is derived recursively from this class with template parameter (K-1). + * In each layer, there is an array: Of type Data for K=1, and of type Index for K>1. + * + * The data array of K=1 contains the values of the array A in lexicographic ordering: + * [0]...[0][0][0], [0]...[0][0][1], ..., [0]...[0][0][something], + * [0]...[0][1][0], [0]...[0][1][1], ..., [0]...[0][1][something], + * ..., + * [0]...[1][0][0], [0]...[1][0][1], ..., [0]...[1][0][something], + * ... ..., + * [1]...[0][0][0], [1]...[0][0][1], ..., [1]...[0][0][something], + * ... ... ... + * Let us call each row in this representation a "last-index list". + * Note that they might have different lengths, so "something" might stand for different + * values here. Last-index lists can also be empty. + * + * The indices array of K=2 contains the indices of the (K=1)-data array at which a new + * last-index list starts. If a last-index list is empty, the are repetitive entries in the + * indices array. + * + * The indices array of K=3 contains the indices of the (K=2)-indices array at which the + * last-but-two index increases by one or drops to zero. If the last-but-two index is increased + * by more than one, there are repetitive entries. + * + * Etc. etc, up to the indices array at layer K. + * + * To form such a structure, we typically iterate twice through the pointer-to-pointer-... + * array: The first time we get to know how much space to reserve in each layer, then we + * allocate it and during the second iteration we copy the data. + */ + +template +class NdFlattener; + +/*! \struct Nd_MPI_Environment + * \brief Contains information for the collective communication of NdFlatteners. + * + * The default arguments in the constructor are chosen in a sensible way: + * - To communicate su2double data, just call Nd_MPI_Environment(). + * - To communicate unsigned long data, call Nd_MPI_Environment(MPI_UNSIGNED_LONG). + */ +struct Nd_MPI_Environment { + using MPI_Allgather_t = decltype(&(SU2_MPI::Allgather)); + using MPI_Allgatherv_t = decltype(&(SU2_MPI::Allgatherv)); + using MPI_Datatype_t = typename SU2_MPI::Datatype; + using MPI_Communicator_t = typename SU2_MPI::Comm; + + const MPI_Datatype_t mpi_data; + const MPI_Datatype_t mpi_index; + MPI_Communicator_t comm; + MPI_Allgather_t MPI_Allgather_fun; + MPI_Allgatherv_t MPI_Allgatherv_fun; + const int rank; + const int size; + + Nd_MPI_Environment(MPI_Datatype_t mpi_data = MPI_DOUBLE, + MPI_Datatype_t mpi_index = MPI_UNSIGNED_LONG, + MPI_Communicator_t comm = SU2_MPI::GetComm(), + MPI_Allgather_t MPI_Allgather_fun = &(SU2_MPI::Allgather), + MPI_Allgatherv_t MPI_Allgatherv_fun = &(SU2_MPI::Allgatherv)) + : mpi_data(mpi_data), + mpi_index(mpi_index), + comm(comm), + MPI_Allgather_fun(MPI_Allgather_fun), + MPI_Allgatherv_fun(MPI_Allgatherv_fun), + rank(SU2_MPI::GetRank()), + size(SU2_MPI::GetSize()) {} +}; + +namespace helpers { +/*! \class IndexAccumulator + * \brief Data structure holding an offset for the NdFlattener, to provide a []...[]-interface. + * \details Derived from IndexAccumulator_Base, specifying the operator[] method: + * - For N==1, the structure has already read all indices but one. So after this method has read the last + * index, return a (possibly const) reference to the data. An additional function data() should be provided. + * - For N>1, more indices have to be read, return an IndexAccumulator. Nd_t_lower is the + * NdFlattener type with one index less. Nd_t_lower is const-qualified if Nd_t is const-qualified, or if the + * index look-up is performed in a const IndexAccumulator. + * \tparam N - Number of missing parameters + * \tparam Nd_t - Type of the accessed NdFlattener, should be NdFlattener + * \tparam Check - if true, raise error if index to operator[] is not in range + */ +/*! \class IndexAccumulator_Base + * \brief Parent class of IndexAccumulator. + * \details IndexAccumulator provides the operator[] method. + */ +template +class IndexAccumulator_Base { + public: + static constexpr size_t N = N_; + using Nd_t = Nd_t_; + using Index_t = typename Nd_t::Index_t; + + /*! \brief Return exclusive upper bound for next index. + */ + Index_t size() const { return size_; } + + protected: + Nd_t& nd; /*!< \brief The accessed NdFlattener. */ + const Index_t offset; /*!< \brief Index in the currently accessed layer. */ + const Index_t size_; /*!< \brief Exclusive upper bound for the next index. */ + + IndexAccumulator_Base(Nd_t& nd, Index_t offset, Index_t size) : nd(nd), offset(offset), size_(size) {} + + FORCEINLINE void CheckBound(Index_t i) const { + assert(i < size()); + if (Check) { + if (i >= size()) SU2_MPI::Error("NdFlattener: Index out of range.", CURRENT_FUNCTION); + } + } +}; + +template +class IndexAccumulator : public IndexAccumulator_Base { + public: + using Base = IndexAccumulator_Base; + static constexpr size_t N = N_; + using Nd_t = Nd_t_; + using Index_t = typename Nd_t::Index_t; + + IndexAccumulator(Nd_t& nd, Index_t offset, Index_t size) : Base(nd, offset, size) {} + + /*! The Base of NdFlattener is NdFlattener, but do also preserve constness. + */ + using Nd_Base_t = su2conditional_t< + std::is_const::value, + const typename Nd_t::Base, + typename Nd_t::Base + >; + /*! Return type of operator[]. */ + using LookupType = IndexAccumulator; + /*! Return type of operator[] const. */ + using LookupType_const = IndexAccumulator; + using Base::nd; + using Base::offset; + using Base::size; + using Base::CheckBound; + + /*! \brief Read one more index, checking whether it is in the range dictated by the NdFlattener and + * previous indices. Non-const version. + * \param[in] i - Index. + */ + LookupType operator[](Index_t i) { + CheckBound(i); + const Index_t new_offset = nd.GetIndices()[offset + i]; + const Index_t new_size = nd.GetIndices()[offset + i + 1] - new_offset; + return LookupType(nd, new_offset, new_size); + } + /*! \brief Read one more index, const version. + * \param[in] i - Index. + */ + LookupType_const operator[](Index_t i) const { + CheckBound(i); + const Index_t new_offset = nd.GetIndices()[offset + i]; + const Index_t new_size = nd.GetIndices()[offset + i + 1] - new_offset; + return LookupType_const(nd, new_offset, new_size); + } +}; + +template +class IndexAccumulator<1, Nd_t_, Check> : public IndexAccumulator_Base<1, Nd_t_, Check> { + public: + using Base = IndexAccumulator_Base<1, Nd_t_, Check>; + static constexpr size_t N = 1; + using Nd_t = Nd_t_; + using Index_t = typename Nd_t::Index_t; + + IndexAccumulator(Nd_t& nd, Index_t offset, Index_t size) : Base(nd, offset, size) {} + + /*! Return type of operator[]. + * \details Data type of NdFlattener, but do also preserve constness. + */ + using LookupType = su2conditional_t< + std::is_const::value, + const typename Nd_t::Data_t, + typename Nd_t::Data_t + >; + using LookupType_const = const typename Nd_t::Data_t; + using Base::nd; + using Base::offset; + using Base::size; + using Base::CheckBound; + + /*! \brief Return (possibly const) reference to the corresponding data element, checking if the index is in its range. + * Non-const version. + * \details The returned reference is const if and only if the type of the accessed NdFlattener is const-qualified. + * Even though the original NdFlattener might be non-const, marking any IndexAccumulator as const during index look-up + * will invoke the const version of operator[], which turns the NdFlattener type to const. + * \param[in] i - Last index. + */ + LookupType& operator[](Index_t i) { + CheckBound(i); + return nd.data()[offset + i]; + } + /*! \brief Return const reference to the corresponding data element, checking if the index is in its range. + * \param[in] i - Last index. + */ + LookupType_const& operator[](Index_t i) const { + CheckBound(i); + return nd.data()[offset + i]; + } + + /*! \brief Return (possibly const) pointer to data, non-const version. + * \details If all indices except the last one are fixed, the corresponding data + * is stored contiguously. Return a pointer to the beginning of the + * block. If this IndexAccumulator was generated from a non-const NdFlattener, the + * pointer is non-const, otherwise it is const. + */ + LookupType* data() { return &(this->operator[](0)); } + /*! \brief Return const pointer to data. + */ + LookupType_const* data() const { return &(this->operator[](0)); } +}; + +} // namespace helpers + +/*! + * \class NdFlattener + * \brief Serialize pointer-to-pointer-... array into one 1D array, keeping track + * of the offsets in few additional 1D arrays. + * + * The pointer-to-pointer-... array can be provided by a nested lambda function + * ('recursive function') or by gathering such arrays from MPI processes ('collective + * communication'). After initializing an NdFlattener with either of these data, + * it can be refreshed in the same way after the the pointer-to-pointer-... array's + * values (but not its structure) have changed. + * + * \tparam K - number of indices + * \tparam Data_t - Type of stored array data + * \tparam Index - Type of index + */ + +template +class NdFlattener : public NdFlattener { + public: + static constexpr size_t K = K_; + using Data_t = Data_t_; + using Index_t = Index_t_; + + using Base = NdFlattener; + using CurrentLayer = NdFlattener; + using LowestLayer = typename Base::LowestLayer; // the K=1 class + + private: + /*! \brief Number of nodes in this layer. + * + * For the layer K=1, nNodes will be the number of data points. + * For a layer K>1, nNodes will be the number of sublists. + */ + Index_t nNodes = 0; + + /*! \brief Iterator used at construction, runs from 0 to (nNodes-1). */ + Index_t iNode = 0; + + /*! \brief Indices in the lower layer's indices or data array */ + std::vector indices; + + /*=== Getters ===*/ + public: + Index_t* GetIndices() { return indices.data(); } + const Index_t* GetIndices() const { return indices.data(); } + + /*=== Outputting ===*/ + + /*! \brief Write in Python-list style. + * + * Like this: [[1, 2], [10, 20, 30]] + */ + friend std::ostream& operator<<(std::ostream& output, NdFlattener const& nd) { + nd.toPythonString_fromto(output, 0, nd.size()); + return output; + } + + protected: + /*! \brief Write to stream in Python-list style, using the data of the + * indices array between 'from' (inclusive) and 'to' (exclusive). + * + * Like this: [[1, 2], [10, 20, 30]] + * \param[in] output - Stream + * \param[in] from - Beginning of the representation in the indices array. + * \param[in] to - Ending of the representation in the indices array. + */ + void toPythonString_fromto(std::ostream& output, Index_t from, Index_t to) const { + output << "["; + for (Index_t i = from; i < to;) { + Base::toPythonString_fromto(output, indices[i], indices[i + 1]); + if (++i < to) output << ", "; + } + output << "]"; + } + + public: + /*! \brief Basic constructor. Afterwards, initialization can be done with initialize_or_refresh. + * + * Called recursively when a derived class (higher K) is constructed. + */ + NdFlattener() {} + + /*! \brief Constructor which calls initialize_or_refresh. + * + */ + template + NdFlattener(ARGS const&... args) { + initialize_or_refresh(args...); + } + + /*! \brief Initialize or refresh the NdFlattener. + * \details Either a 'recursive function' or 'collective communication' + * may be used. When the NdFlattener does not hold data yet, it is + * initialized, meaning that the data are collected and the indices arrays + * are allocated and filled. Otherwise it is refreshed, meaning that the data are + * recollected under the assumption that the indices arrays did not change. + */ + template + void initialize_or_refresh(ARGS const&... args) { + if (initialized()) { + refresh(args...); + } else { + initialize(args...); + } + } + + /*! \brief Initialization status of the NdFlattener. + * \returns true if the NdFlattener has been initialized + */ + bool initialized() { return nNodes > 0; } + + protected: + /*! \brief Allocate the indices array after \a nNodes has been determined. + */ + void allocate() { + indices.resize(nNodes + 1); + indices[0] = 0; + Base::allocate(); + } + + /*! \brief Set \a iNode to 0 in all layers. + */ + void reset_iNode() { + iNode = 0; + Base::reset_iNode(); + } + + /*=== Construct from 'recursive function' ===*/ + public: + /*! \brief Initialize from a 'recursive function'. + * + * The function should return a pair. Its first entry is the number of children. + * Its second entry is a function with the same meaning, recursively + * one layer down. + * \param f - the 'recursive function' + */ + template + void initialize(f_type f) { + count_f(f); + allocate(); + set_f(f, false); + } + + /*! \brief Refresh the data according to the 'recursive function' + * + * The NdFlattener must have been constructed with a 'recursive function'. + * Now refresh the values with another 'recursive function'. The subarray lengths + * resulting from both 'recursive functions' must coincide, as the indices arrays + * are not changed. + * + * \param f - the 'recursive function' + * \tparam f_type - to allow for any type of the 'recursive function' + */ + template + void refresh(f_type f) { + reset_iNode(); + set_f(f, true); + } + + protected: + /*! \brief Determine the space required for reading the 'recursive function'. + * + * \param f - the 'recursive function' + */ + template + void count_f(f_type f) { + Index_t nChild = f.first; + for (Index_t iChild = 0; iChild < nChild; iChild++) { + nNodes++; + Base::count_f(f.second(iChild)); + } + } + + /*! \brief Read the 'recursive function' into the allocated arrays. + * + * \param f - the 'recursive function' + * \param refresh - if true, the object is already initialized and only the data + * in layer 1 have to be overwritten + * \tparam f_type - to allow for any type of the 'recursive function' + */ + template + void set_f(f_type f, bool refresh) { + Index_t nChild = f.first; + for (Index_t iChild = 0; iChild < nChild; iChild++) { + Base::set_f(f.second(iChild), refresh); + if (!refresh) { + indices[iNode + 1] = indices[iNode] + f.second(iChild).first; + } else { + if (indices[iNode + 1] != indices[iNode] + f.second(iChild).first) { + SU2_MPI::Error("NdFlattener: Structure has changed, cannot refresh.", CURRENT_FUNCTION); + } + } + iNode++; + } + } + + /*=== Construct with Allgatherv ===*/ + + public: + /*! \brief Initialize a flattener with K indices by combining distributed flatteners with (K-1) indices each. + * + * The new first index will encode the rank of the process. Data is exchanged in MPI::Allgatherv-style + * collective communication. + * \param[in] mpi_env - The MPI environment used for communication. + * \param[in] local_version - The local NdFlattener structure with (K-1) indices. + */ + template + void initialize(MPI_Environment_type const& mpi_env, Base const& local_version) { + // [k][r] is number of all nodes in layer (k+1), rank r in the new structure + su2matrix Nodes_all(K, mpi_env.size); + // the first index decides on the rank, so there is exactly one node per rank + for (int r = 0; r < mpi_env.size; r++) { + nNodes += Nodes_all[K - 1][r] = 1; + } + // set the lower layers' nNodes and Nodes_all[k] + Base::count_g(mpi_env, Nodes_all, local_version); + + allocate(); + + indices[0] = 0; + for (int r = 0; r < mpi_env.size; r++) { + indices[r + 1] = indices[r] + Nodes_all[K - 2][r]; + } + Base::set_g(mpi_env, Nodes_all, local_version); + } + + /*! \brief Refresh the data by MPI collective communication. + * + * The NdFlattener must have been constructed by MPI collective communication. + * Now refresh the values with another collective communication. The subarray lengths + * resulting from both collective communications must coincide, as the indices arrays + * are not changed. + * \param[in] mpi_env - The MPI environment used for communication. + * \param[in] local_version - The local NdFlattener structure. + */ + template + void refresh(MPI_Environment_type const& mpi_env, Base const& local_version) { + su2matrix Nodes_all_0(1, mpi_env.size); + LowestLayer::count_g(mpi_env, Nodes_all_0, local_version); + LowestLayer::set_g(mpi_env, Nodes_all_0, local_version); + } + + protected: + /*! \brief Count the distributed flatteners' numbers of nodes, and set nNodes. + * + * \param[in] mpi_env - MPI environment for communication + * \param[out] Nodes_all - [k][r] is set to number of nodes in layer (k+1), rank r. + * \param[in] local_version - local instance to be send to the other processes + */ + void count_g(Nd_MPI_Environment const& mpi_env, su2matrix& Nodes_all, CurrentLayer const& local_version) { + nNodes = 0; + // gather numbers of nodes in the current layer from all processes + mpi_env.MPI_Allgather_fun(&(local_version.nNodes), 1, mpi_env.mpi_index, Nodes_all[K - 1], 1, mpi_env.mpi_index, + mpi_env.comm); + for (int r = 0; r < mpi_env.size; r++) { + nNodes += Nodes_all[K - 1][r]; + } + Base::count_g(mpi_env, Nodes_all, local_version); + } + + /*! \brief Gather the distributed flatteners' data and index arrays into the allocated arrays. + * + * \param[in] mpi_env - MPI environment for communication + * \param[in] Nodes_all - [k][r] is the number of nodes in layer (k+1), rank r. + * \param[in] local_version - local instance to be sent to the other processes + */ + void set_g(Nd_MPI_Environment const& mpi_env, su2matrix const& Nodes_all, + CurrentLayer const& local_version) { + std::vector Nodes_all_K_as_int(mpi_env.size); + std::vector Nodes_all_k_cumulated( mpi_env.size + 1); + //< [r] is the number of nodes in the current layer, summed over all processes with rank below r, **plus one**. + // Used as displacements in Allgatherv, as we do not want to transfer the initial zeros, but we want to transfer the + // last element of indices, which is the local nNodes of the layer below. Note that MPI needs indices of type 'int'. + Nodes_all_k_cumulated[0] = 1; + for (int r = 0; r < mpi_env.size; r++) { + Nodes_all_k_cumulated[r + 1] = Nodes_all_k_cumulated[r] + Nodes_all[K - 1][r]; + Nodes_all_K_as_int[r] = Nodes_all[K - 1][r]; + } + mpi_env.MPI_Allgatherv_fun(local_version.indices.data() + 1, Nodes_all[K - 1][mpi_env.rank], mpi_env.mpi_index, + indices.data(), Nodes_all_K_as_int.data(), Nodes_all_k_cumulated.data(), + mpi_env.mpi_index, mpi_env.comm); + // shift indices + for (int r = 1; r < mpi_env.size; r++) { + Index_t first_entry_to_be_shifted = Nodes_all_k_cumulated[r]; + Index_t last_entry_to_be_shifted = Nodes_all_k_cumulated[r + 1] - 1; + Index_t shift = indices[first_entry_to_be_shifted - 1]; + for (Index_t i = first_entry_to_be_shifted; i <= last_entry_to_be_shifted; i++) { + indices[i] += shift; + } + } + + Base::set_g(mpi_env, Nodes_all, local_version); + } + + /*== Data access ==*/ + public: + Index_t size() const { // should not be called by recursion, is incorrect in lower layers! + return nNodes; + } + + /*! \brief Look-up with IndexAccumulator, non-const version. + */ + helpers::IndexAccumulator > operator[](Index_t i0) { + return helpers::IndexAccumulator >(*this, 0, size())[i0]; + } + /*! \brief Look-up with IndexAccumulator, const version. + */ + helpers::IndexAccumulator > operator[](Index_t i0) const { + return helpers::IndexAccumulator >(*this, 0, size())[i0]; + } +}; + +template +class NdFlattener<1, Data_t_, Index_t_> { + public: + static constexpr size_t K = 1; + using Data_t = Data_t_; + using Index_t = Index_t_; + + using CurrentLayer = NdFlattener<1, Data_t, Index_t>; + using LowestLayer = CurrentLayer; + + private: + Index_t nNodes = 0; + Index_t iNode = 0; + std::vector data_; + + /*=== Outputting ===*/ + protected: + void toPythonString_fromto(std::ostream& output, Index_t from, Index_t to) const { + output << "["; + for (Index_t i = from; i < to;) { + output << data_[i]; + if (++i < to) output << ", "; + } + output << "]"; + } + + public: + NdFlattener(void) {} + + template + NdFlattener(ARGS const&... args) { + initialize_or_refresh(args...); + } + + template + void initialize_or_refresh(ARGS const&... args) { + if (initialized()) { + refresh(args...); + } else { + initialize(args...); + } + } + + bool initialized() { return nNodes > 0; } + + // Functionality to initialize/refresh from a recursive function + // could be desirable also for N=1, in order to gather from such + // NdFlatteners an NdFlattener with N=2. + // Gathering an NdFlattener with N=1 is not meaningful however. + + template + void initialize(f_type f) { + count_f(f); + allocate(); + set_f(f, false); + } + + template + void refresh(f_type f) { + reset_iNode(); + set_f(f, true); + } + + protected: + void allocate() { data_.resize(nNodes); } + + void reset_iNode() { iNode = 0; } + + /*=== Construct from 'recursive function' ===*/ + protected: + template + void count_f(f_type f) { + nNodes += f.first; + } + + template + void set_f(f_type f, bool refresh) { + Index_t nChild = f.first; + for (Index_t iChild = 0; iChild < nChild; iChild++) { + data_[iNode] = f.second(iChild); + iNode++; + } + } + + /*=== Construct with Allgatherv ===*/ + protected: + void count_g(Nd_MPI_Environment const& mpi_env, su2matrix& Nodes_all, CurrentLayer const& local_version) { + nNodes = 0; + // gather numbers of nodes in the current layer from all processes + mpi_env.MPI_Allgather_fun(&(local_version.nNodes), 1, mpi_env.mpi_index, Nodes_all[0], 1, mpi_env.mpi_index, + mpi_env.comm); + for (int r = 0; r < mpi_env.size; r++) { + nNodes += Nodes_all[0][r]; + } + } + + void set_g(Nd_MPI_Environment const& mpi_env, su2matrix const& Nodes_all, + CurrentLayer const& local_version) { + std::vector Nodes_all_0_as_int(mpi_env.size); + std::vector Nodes_all_0_cumulated(mpi_env.size + 1); + Nodes_all_0_cumulated[0] = 0; + for (int r = 0; r < mpi_env.size; r++) { + Nodes_all_0_cumulated[r + 1] = Nodes_all_0_cumulated[r] + Nodes_all[0][r]; + Nodes_all_0_as_int[r] = Nodes_all[0][r]; + } + + mpi_env.MPI_Allgatherv_fun(local_version.data_.data(), Nodes_all[0][mpi_env.rank], mpi_env.mpi_data, data_.data(), + Nodes_all_0_as_int.data(), Nodes_all_0_cumulated.data(), mpi_env.mpi_data, mpi_env.comm); + } + + /*== Access to data ==*/ + // Calling the following functions is a bit strange, because if you have only one level, + // you do not really benefit from NdFlattener's functionality. + public: + Index_t size() const { // should not be called by recursion, is incorrect in lower layers! + return nNodes; + } + /*! \brief Data look-up, non-const version. + */ + Data_t& operator[](Index_t i0) { return data_[i0]; } + /*! \brief Data look-up, const version. + */ + const Data_t& operator[](Index_t i0) const { return data_[i0]; } + + Data_t* data() { return data_.data(); } + + const Data_t* data() const { return data_.data(); } +}; diff --git a/Common/src/CConfig.cpp b/Common/src/CConfig.cpp index 777cd24e08e..3eaed4c333f 100644 --- a/Common/src/CConfig.cpp +++ b/Common/src/CConfig.cpp @@ -531,7 +531,7 @@ void CConfig::addActDiskOption(const string & name, unsigned short & nMarker_Act } void CConfig::addWallFunctionOption(const string &name, unsigned short &list_size, string* &string_field, - unsigned short* &val_Kind_WF, unsigned short** &val_IntInfo_WF, + WALL_FUNCTIONS* &val_Kind_WF, unsigned short** &val_IntInfo_WF, su2double** &val_DoubleInfo_WF) { assert(option_map.find(name) == option_map.end()); all_options.insert(pair(name, true)); @@ -1223,6 +1223,10 @@ void CConfig::SetConfig_Options() { addDoubleOption("PRANDTL_LAM", Prandtl_Lam, 0.72); /*!\brief PRANDTL_TURB \n DESCRIPTION: Turbulent Prandtl number (0.9 (air), only for compressible flows) \n DEFAULT 0.90 \ingroup Config*/ addDoubleOption("PRANDTL_TURB", Prandtl_Turb, 0.90); + /*!\brief WALLMODELKAPPA \n DESCRIPTION: von Karman constant used for the wall model \n DEFAULT 0.41 \ingroup Config*/ + addDoubleOption("WALLMODELKAPPA", wallModelKappa, 0.41); + /*!\brief WALLMODELB \n DESCRIPTION: constant B used for the wall model \n DEFAULT 5.0 \ingroup Config*/ + addDoubleOption("WALLMODELB", wallModelB, 5.5); /*!\brief BULK_MODULUS \n DESCRIPTION: Value of the Bulk Modulus \n DEFAULT 1.42E5 \ingroup Config*/ addDoubleOption("BULK_MODULUS", Bulk_Modulus, 1.42E5); /* DESCRIPTION: Epsilon^2 multipier in Beta calculation for incompressible preconditioner. */ @@ -3258,13 +3262,13 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i Wall_Functions = false; if (nMarker_WallFunctions > 0) { for (iMarker = 0; iMarker < nMarker_WallFunctions; iMarker++) { - if (Kind_WallFunctions[iMarker] != NO_WALL_FUNCTION) + if (Kind_WallFunctions[iMarker] != WALL_FUNCTIONS::NONE) Wall_Functions = true; - if ((Kind_WallFunctions[iMarker] == ADAPTIVE_WALL_FUNCTION) || (Kind_WallFunctions[iMarker] == SCALABLE_WALL_FUNCTION) - || (Kind_WallFunctions[iMarker] == NONEQUILIBRIUM_WALL_MODEL)) + if ((Kind_WallFunctions[iMarker] == WALL_FUNCTIONS::ADAPTIVE_FUNCTION) || (Kind_WallFunctions[iMarker] == WALL_FUNCTIONS::SCALABLE_FUNCTION) + || (Kind_WallFunctions[iMarker] == WALL_FUNCTIONS::NONEQUILIBRIUM_MODEL)) - SU2_MPI::Error(string("For RANS problems, use NO_WALL_FUNCTION, STANDARD_WALL_FUNCTION or EQUILIBRIUM_WALL_MODEL.\n"), CURRENT_FUNCTION); + SU2_MPI::Error(string("For RANS problems, use NONE, STANDARD_WALL_FUNCTION or EQUILIBRIUM_WALL_MODEL.\n"), CURRENT_FUNCTION); } } @@ -4662,8 +4666,8 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i SU2_MPI::Error("Streamwise Periodic Flow currently only implemented for incompressible flow.", CURRENT_FUNCTION); if (Kind_Solver == INC_EULER) SU2_MPI::Error("Streamwise Periodic Flow + Incompressible Euler: Not tested yet.", CURRENT_FUNCTION); - if (nMarker_PerBound != 2) - SU2_MPI::Error("Streamwise Periodic Flow currently only implemented for one Periodic Marker pair. Combining Streamwise and Spanwise periodicity not possible in the moment.", CURRENT_FUNCTION); + if (nMarker_PerBound == 0) + SU2_MPI::Error("A MARKER_PERIODIC pair has to be set with KIND_STREAMWISE_PERIODIC != NONE.", CURRENT_FUNCTION); if (Energy_Equation && Streamwise_Periodic_Temperature && nMarker_Isothermal != 0) SU2_MPI::Error("No MARKER_ISOTHERMAL marker allowed with STREAMWISE_PERIODIC_TEMPERATURE= YES, only MARKER_HEATFLUX & MARKER_SYM.", CURRENT_FUNCTION); if (DiscreteAdjoint && Kind_Streamwise_Periodic == ENUM_STREAMWISE_PERIODIC::MASSFLOW) @@ -4873,16 +4877,10 @@ void CConfig::SetPostprocessing(SU2_COMPONENT val_software, unsigned short val_i Kind_Linear_Solver = Kind_DiscAdj_Linear_Solver; Kind_Linear_Solver_Prec = Kind_DiscAdj_Linear_Prec; - if (TimeMarching != TIME_MARCHING::STEADY) { + if (Time_Domain) { Restart_Flow = false; - if (GetKind_GridMovement() != RIGID_MOTION && - GetKind_GridMovement() != NO_MOVEMENT) { - SU2_MPI::Error(string("Dynamic mesh movement currently only supported for the discrete adjoint solver for\n") + - string("GRID_MOVEMENT = RIGID_MOTION."), CURRENT_FUNCTION); - } - if (Unst_AdjointIter- long(nTimeIter) < 0){ SU2_MPI::Error(string("Invalid iteration number requested for unsteady adjoint.\n" ) + string("Make sure EXT_ITER is larger or equal than UNST_ADJOINT_ITER."), @@ -7826,7 +7824,7 @@ CConfig::~CConfig(void) { } -string CConfig::GetFilename(string filename, string ext, unsigned long Iter) const { +string CConfig::GetFilename(string filename, string ext, int Iter) const { /*--- Remove any extension --- */ @@ -7846,7 +7844,7 @@ string CConfig::GetFilename(string filename, string ext, unsigned long Iter) con filename = GetMultiInstance_FileName(filename, GetiInst(), ext); if (GetTime_Domain()){ - filename = GetUnsteady_FileName(filename, (int)Iter, ext); + filename = GetUnsteady_FileName(filename, Iter, ext); } return filename; @@ -8877,9 +8875,9 @@ pair CConfig::GetWallRoughnessProperties(string val_marker return WallProp; } -unsigned short CConfig::GetWallFunction_Treatment(string val_marker) const { +WALL_FUNCTIONS CConfig::GetWallFunction_Treatment(string val_marker) const { - unsigned short WallFunction = NO_WALL_FUNCTION; + WALL_FUNCTIONS WallFunction = WALL_FUNCTIONS::NONE; for(unsigned short iMarker=0; iMarker inputValues; - std::vector localInputValues; - std::vector localOutputValues; - TapePosition StartPosition, EndPosition; std::vector TapePositions; diff --git a/Common/src/fem/fem_geometry_structure.cpp b/Common/src/fem/fem_geometry_structure.cpp index e1409697c8f..f7b051cab69 100644 --- a/Common/src/fem/fem_geometry_structure.cpp +++ b/Common/src/fem/fem_geometry_structure.cpp @@ -6128,7 +6128,7 @@ void CMeshFEM_DG::WallFunctionPreprocessing(CConfig *config) { case ISOTHERMAL: case HEAT_FLUX: { const string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if(config->GetWallFunction_Treatment(Marker_Tag) != NO_WALL_FUNCTION) + if(config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) wallFunctions = true; break; } @@ -6235,19 +6235,19 @@ void CMeshFEM_DG::WallFunctionPreprocessing(CConfig *config) { case ISOTHERMAL: case HEAT_FLUX: { const string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if(config->GetWallFunction_Treatment(Marker_Tag) != NO_WALL_FUNCTION) { + if(config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) { /* An LES wall model is used for this boundary marker. Determine which wall model and allocate the memory for the member variable. */ switch (config->GetWallFunction_Treatment(Marker_Tag) ) { - case EQUILIBRIUM_WALL_MODEL: { + case WALL_FUNCTIONS::EQUILIBRIUM_MODEL: { if(rank == MASTER_NODE) cout << "Marker " << Marker_Tag << " uses an Equilibrium Wall Model." << endl; boundaries[iMarker].wallModel = new CWallModel1DEQ(config, Marker_Tag); break; } - case LOGARITHMIC_WALL_MODEL: { + case WALL_FUNCTIONS::LOGARITHMIC_MODEL: { if(rank == MASTER_NODE) cout << "Marker " << Marker_Tag << " uses the Reichardt and Kader analytical laws for the Wall Model." << endl; diff --git a/Common/src/fem/fem_wall_distance.cpp b/Common/src/fem/fem_wall_distance.cpp index b4d2c70c1a0..d8830797e5f 100644 --- a/Common/src/fem/fem_wall_distance.cpp +++ b/Common/src/fem/fem_wall_distance.cpp @@ -172,7 +172,7 @@ void CMeshFEM_DG::SetWallDistance(su2double val){ } } -void CMeshFEM_DG::SetWallDistance(const CConfig *config, CADTElemClass *WallADT){ +void CMeshFEM_DG::SetWallDistance(CADTElemClass *WallADT, const CConfig* config, unsigned short iZone){ /*--------------------------------------------------------------------------*/ /*--- Step 3: Determine the wall distance of the integration points of ---*/ diff --git a/Common/src/fem/geometry_structure_fem_part.cpp b/Common/src/fem/geometry_structure_fem_part.cpp index 9f0384b6873..ad4085eb773 100644 --- a/Common/src/fem/geometry_structure_fem_part.cpp +++ b/Common/src/fem/geometry_structure_fem_part.cpp @@ -3355,7 +3355,7 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig *config) { case ISOTHERMAL: case HEAT_FLUX: { const string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if(config->GetWallFunction_Treatment(Marker_Tag) != NO_WALL_FUNCTION) + if(config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) wallFunctions = true; break; } @@ -3500,7 +3500,7 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig *config) { case ISOTHERMAL: case HEAT_FLUX: { const string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if(config->GetWallFunction_Treatment(Marker_Tag) != NO_WALL_FUNCTION) { + if(config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) { /* Retrieve the floating point information for this boundary marker. The exchange location is the first element of this array. */ @@ -3952,7 +3952,7 @@ void CPhysicalGeometry::DetermineDonorElementsWallFunctions(CConfig *config) { case ISOTHERMAL: case HEAT_FLUX: { const string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if(config->GetWallFunction_Treatment(Marker_Tag) != NO_WALL_FUNCTION) { + if(config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) { for(unsigned long l=0; lRemoveMultipleDonorsWallFunctions(); @@ -4825,7 +4825,7 @@ void CPhysicalGeometry::ComputeFEMGraphWeights( case ISOTHERMAL: case HEAT_FLUX: { const string Marker_Tag = config->GetMarker_All_TagBound(iMarker); - if(config->GetWallFunction_Treatment(Marker_Tag) != NO_WALL_FUNCTION) { + if(config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) { /* Retrieve the integer information for this boundary marker. The number of points in normal direction for the wall function diff --git a/Common/src/geometry/CGeometry.cpp b/Common/src/geometry/CGeometry.cpp index cf708b8a112..07634cd1850 100644 --- a/Common/src/geometry/CGeometry.cpp +++ b/Common/src/geometry/CGeometry.cpp @@ -29,6 +29,7 @@ #include "../../include/geometry/elements/CElement.hpp" #include "../../include/parallelization/omp_structure.hpp" #include "../../include/toolboxes/geometry_toolbox.hpp" +#include "../../include/toolboxes/ndflattener.hpp" CGeometry::CGeometry(void) : size(SU2_MPI::GetSize()), @@ -2475,18 +2476,12 @@ void CGeometry::ComputeAirfoil_Section(su2double *Plane_P0, su2double *Plane_Nor } -void CGeometry::RegisterCoordinates(const CConfig *config) const { +void CGeometry::RegisterCoordinates() const { const bool input = true; - const bool push_index = config->GetMultizone_Problem()? false : true; SU2_OMP_FOR_STAT(roundUpDiv(nPoint,omp_get_num_threads())) for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - for (auto iDim = 0u; iDim < nDim; iDim++) { - AD::RegisterInput(nodes->GetCoord(iPoint)[iDim], push_index); - } - if(!push_index) { - nodes->SetIndex(iPoint, input); - } + nodes->RegisterCoordinates(iPoint, input); } END_SU2_OMP_FOR } @@ -2495,10 +2490,6 @@ void CGeometry::UpdateGeometry(CGeometry **geometry_container, CConfig *config) geometry_container[MESH_0]->InitiateComms(geometry_container[MESH_0], config, COORDINATES); geometry_container[MESH_0]->CompleteComms(geometry_container[MESH_0], config, COORDINATES); - if (config->GetDynamic_Grid()){ - geometry_container[MESH_0]->InitiateComms(geometry_container[MESH_0], config, GRID_VELOCITY); - geometry_container[MESH_0]->CompleteComms(geometry_container[MESH_0], config, GRID_VELOCITY); - } geometry_container[MESH_0]->SetControlVolume(config, UPDATE); geometry_container[MESH_0]->SetBoundControlVolume(config, UPDATE); @@ -2731,8 +2722,6 @@ void CGeometry::ComputeSurf_Curvature(CConfig *config) { su2double U[3] = {0.0}, V[3] = {0.0}, W[3] = {0.0}, Length_U, Length_V, Length_W, CosValue, Angle_Value, *K, *Angle_Defect, *Area_Vertex, *Angle_Alpha, *Angle_Beta, **NormalMeanK, MeanK, GaussK, MaxPrinK, cot_alpha, cot_beta, delta, X1, X2, X3, Y1, Y2, Y3, radius, *Buffer_Send_Coord, *Buffer_Receive_Coord, *Coord, Dist, MinDist, MaxK, MinK, SigmaK; bool *Check_Edge; - const bool fea = config->GetStructuralProblem(); - /*--- Allocate surface curvature ---*/ K = new su2double [nPoint]; for (iPoint = 0; iPoint < nPoint; iPoint++) K[iPoint] = 0.0; @@ -2996,7 +2985,7 @@ void CGeometry::ComputeSurf_Curvature(CConfig *config) { SigmaK = sqrt(SigmaK/su2double(TotalnPointDomain)); - if ((rank == MASTER_NODE) && (!fea)) + if (rank == MASTER_NODE) cout << "Max K: " << MaxK << ". Mean K: " << MeanK << ". Standard deviation K: " << SigmaK << "." << endl; Point_Critical.clear(); @@ -3922,15 +3911,14 @@ void CGeometry::ComputeWallDistance(const CConfig* const* config_container, CGeo /*--- Loop over all zones and compute the ADT based on the viscous walls in that zone ---*/ for (int iZone = 0; iZone < nZone; iZone++){ - CGeometry *geometry = geometry_container[iZone][iInst][MESH_0]; - unique_ptr WallADT = geometry->ComputeViscousWallADT(config_container[iZone]); + unique_ptr WallADT = geometry_container[iZone][iInst][MESH_0]->ComputeViscousWallADT(config_container[iZone]); if (WallADT && !WallADT->IsEmpty()){ allEmpty = false; /*--- Inner loop over all zones to update the wall distances. * It might happen that there is a closer viscous wall in zone iZone for points in zone jZone. ---*/ for (int jZone = 0; jZone < nZone; jZone++){ if (wallDistanceNeeded[jZone]) - geometry_container[jZone][iInst][MESH_0]->SetWallDistance(config_container[jZone], WallADT.get()); + geometry_container[jZone][iInst][MESH_0]->SetWallDistance(WallADT.get(), config_container[jZone], iZone); } } } @@ -3942,5 +3930,28 @@ void CGeometry::ComputeWallDistance(const CConfig* const* config_container, CGeo geometry->SetWallDistance(0.0); } } + /*--- Otherwise, set wall roughnesses. ---*/ + if(!allEmpty){ + /*--- Store all wall roughnesses in a common data structure. ---*/ + // [iZone][iMarker] -> roughness, for this rank + auto roughness_f = + make_pair( nZone, [config_container,geometry_container,iInst](unsigned long iZone){ + const CConfig* config = config_container[iZone]; + const auto nMarker = geometry_container[iZone][iInst][MESH_0]->GetnMarker(); + + return make_pair( nMarker, [config](unsigned long iMarker){ + return config->GetWallRoughnessProperties(config->GetMarker_All_TagBound(iMarker)).second; + }); + }); + NdFlattener<2> roughness_local(roughness_f); + // [rank][iZone][iMarker] -> roughness + NdFlattener<3> roughness_global(Nd_MPI_Environment(), roughness_local); + // use it to update roughnesses + for(int jZone=0; jZoneGetnRoughWall()>0){ + geometry_container[jZone][iInst][MESH_0]->nodes->SetWallRoughness(roughness_global); + } + } + } } } diff --git a/Common/src/geometry/CPhysicalGeometry.cpp b/Common/src/geometry/CPhysicalGeometry.cpp index 75db70bc909..5bebaded5f0 100644 --- a/Common/src/geometry/CPhysicalGeometry.cpp +++ b/Common/src/geometry/CPhysicalGeometry.cpp @@ -11017,16 +11017,13 @@ std::unique_ptr CPhysicalGeometry::ComputeViscousWallADT(const CC } -void CPhysicalGeometry::SetWallDistance(const CConfig *config, CADTElemClass *WallADT) { +void CPhysicalGeometry::SetWallDistance(CADTElemClass* WallADT, const CConfig* config, unsigned short iZone) { /*--------------------------------------------------------------------------*/ /*--- Step 3: Loop over all interior mesh nodes and compute minimum ---*/ /*--- distance to a solid wall element ---*/ /*--------------------------------------------------------------------------*/ - /*--- Store marker list and roughness in a global array. ---*/ - if (config->GetnRoughWall() > 0) SetGlobalMarkerRoughness(config); - SU2_OMP_PARALLEL if (!WallADT->IsEmpty()) { /*--- Solid wall boundary nodes are present. Compute the wall @@ -11041,49 +11038,11 @@ void CPhysicalGeometry::SetWallDistance(const CConfig *config, CADTElemClass *Wa WallADT->DetermineNearestElement(nodes->GetCoord(iPoint), dist, markerID, elemID, rankID); - nodes->SetWall_Distance(iPoint, min(dist,nodes->GetWall_Distance(iPoint))); - - if (config->GetnRoughWall() > 0) { - auto index = GlobalMarkerStorageDispl[rankID] + markerID; - auto localRoughness = GlobalRoughness_Height[index]; - nodes->SetRoughnessHeight(iPoint, localRoughness); + if(dist < nodes->GetWall_Distance(iPoint)){ + nodes->SetWall_Distance(iPoint, dist, rankID, iZone, markerID, elemID); } } END_SU2_OMP_FOR - } END_SU2_OMP_PARALLEL } - -void CPhysicalGeometry::SetGlobalMarkerRoughness(const CConfig* config) { - - const auto nMarker_All = config->GetnMarker_All(); - - vector recvCounts(size); - auto sizeLocal = static_cast(nMarker_All); // number of local markers - - /*--- Communicate size of local marker array and make an array large enough to hold all data. ---*/ - SU2_MPI::Allgather(&sizeLocal, 1, MPI_INT, recvCounts.data(), 1, MPI_INT, SU2_MPI::GetComm()); - - /*--- Set the global array of displacements, needed to access the correct roughness element. ---*/ - GlobalMarkerStorageDispl.resize(size); - GlobalMarkerStorageDispl[0] = 0; - for (int iRank = 1; iRank < size; iRank++) - GlobalMarkerStorageDispl[iRank] = GlobalMarkerStorageDispl[iRank-1] + recvCounts[iRank-1]; - - /*--- Total size ---*/ - const auto sizeGlobal = GlobalMarkerStorageDispl[size-1] + recvCounts[size-1]; - - /*--- Allocate local and global arrays to hold roughness. ---*/ - vector localRough(nMarker_All); // local number of markers - GlobalRoughness_Height.resize(sizeGlobal); // all markers including send recieve - - for (auto iMarker = 0u; iMarker < nMarker_All; iMarker++) { - auto wallprop = config->GetWallRoughnessProperties(config->GetMarker_All_TagBound(iMarker)); - localRough[iMarker] = wallprop.second; - } - - /*--- Finally, gather the roughness of all markers. ---*/ - SU2_MPI::Allgatherv(localRough.data(), sizeLocal, MPI_DOUBLE, GlobalRoughness_Height.data(), - recvCounts.data(), GlobalMarkerStorageDispl.data(), MPI_DOUBLE, SU2_MPI::GetComm()); -} diff --git a/Common/src/geometry/dual_grid/CPoint.cpp b/Common/src/geometry/dual_grid/CPoint.cpp index 810f60321b6..19ec490c29e 100644 --- a/Common/src/geometry/dual_grid/CPoint.cpp +++ b/Common/src/geometry/dual_grid/CPoint.cpp @@ -66,9 +66,14 @@ void CPoint::FullAllocation(unsigned short imesh, const CConfig *config) { if (config->GetTime_Marching() != TIME_MARCHING::STEADY) { Volume_n.resize(npoint) = su2double(0.0); Volume_nM1.resize(npoint) = su2double(0.0); + if (config->GetDynamic_Grid() && config->GetDiscrete_Adjoint()) { + Volume_Old.resize(npoint) = su2double(0.0); + Volume_n_Old.resize(npoint) = su2double(0.0); + Volume_nM1_Old.resize(npoint) = su2double(0.0); + } } - if(config->GetAD_Mode() && config->GetMultizone_Problem()) { + if (config->GetDiscrete_Adjoint()) { AD_InputIndex.resize(npoint,nDim) = 0; AD_OutputIndex.resize(npoint,nDim) = 0; } @@ -125,7 +130,13 @@ void CPoint::FullAllocation(unsigned short imesh, const CConfig *config) { nNeighbor.resize(npoint) = 0; MaxLength.resize(npoint) = su2double(0.0); Curvature.resize(npoint) = su2double(0.0); + Wall_Distance.resize(npoint) = su2double(0.0); + ClosestWall_Rank.resize(npoint) = -1; + ClosestWall_Zone.resize(npoint) = numeric_limits::max(); + ClosestWall_Marker = ClosestWall_Zone; + ClosestWall_Elem.resize(npoint) = numeric_limits::max(); + RoughnessHeight.resize(npoint) = su2double(0.0); SharpEdge_Distance.resize(npoint) = su2double(0.0); @@ -142,17 +153,6 @@ void CPoint::SetPoints(const vector >& pointsMatrix) { Edge = CCompressedSparsePatternL(Point.outerPtr(), Point.outerPtr()+Point.getOuterSize()+1, long(-1)); } -void CPoint::SetIndex(unsigned long iPoint, bool input) { - for (unsigned long iDim = 0; iDim < nDim; iDim++) { - if(input) { - AD::SetIndex(AD_InputIndex(iPoint,iDim), Coord(iPoint,iDim)); - } - else { - AD::SetIndex(AD_OutputIndex(iPoint,iDim), Coord(iPoint,iDim)); - } - } -} - void CPoint::SetVolume_n() { assert(Volume_n.size() == Volume.size()); parallelCopy(Volume.size(), Volume.data(), Volume_n.data()); @@ -163,6 +163,31 @@ void CPoint::SetVolume_nM1() { parallelCopy(Volume_n.size(), Volume_n.data(), Volume_nM1.data()); } +void CPoint::SetVolume_Old() { + assert(Volume_Old.size() == Volume.size()); + parallelCopy(Volume.size(), Volume.data(), Volume_Old.data()); +} + +void CPoint::SetVolume_n_Old() { + assert(Volume_n_Old.size() == Volume_n.size()); + parallelCopy(Volume_n.size(), Volume_n.data(), Volume_n_Old.data()); +} + +void CPoint::SetVolume_nM1_Old() { + assert(Volume_nM1_Old.size() == Volume_nM1.size()); + parallelCopy(Volume_nM1.size(), Volume_nM1.data(), Volume_nM1_Old.data()); +} + +void CPoint::SetVolume_n_from_OldnM1() { + assert(Volume_n.size() == Volume_nM1_Old.size()); + parallelCopy(Volume_nM1_Old.size(), Volume_nM1_Old.data(), Volume_n.data()); +} + +void CPoint::SetVolume_from_Oldn() { + assert(Volume.size() == Volume_n_Old.size()); + parallelCopy(Volume_n_Old.size(), Volume_n_Old.data(), Volume.data()); +} + void CPoint::SetCoord_n() { assert(Coord_n.size() == Coord.size()); parallelCopy(Coord.size(), Coord.data(), Coord_n.data()); @@ -179,3 +204,4 @@ void CPoint::SetCoord_Old() { } void CPoint::SetCoord_SumZero() { parallelSet(Coord_Sum.size(), 0.0, Coord_Sum.data()); } + diff --git a/Common/src/grid_movement/CVolumetricMovement.cpp b/Common/src/grid_movement/CVolumetricMovement.cpp index 7be3d23435d..ee019127107 100644 --- a/Common/src/grid_movement/CVolumetricMovement.cpp +++ b/Common/src/grid_movement/CVolumetricMovement.cpp @@ -356,68 +356,8 @@ void CVolumetricMovement::ComputenNonconvexElements(CGeometry *geometry, bool Sc nNonconvexElements++; } } - } else if (false) { - - /*--- 3D elements ---*/ - unsigned short iNode, iFace, nFaceNodes; - - for (iElem = 0; iElem < geometry->GetnElem(); iElem++){ - for (iFace = 0; iFace < geometry->elem[iElem]->GetnFaces(); iFace++){ - nFaceNodes = geometry->elem[iElem]->GetnNodesFace(iFace); - - su2double minCrossProductLength = 1.e6, maxCrossProductLength = -1.e6; - for (iNode = 0; iNode < nFaceNodes; iNode++) { - su2double crossProductLength = 0.0; - - /*--- Get coords of node face_point_i and its adjacent nodes in the face ---*/ - unsigned long face_point_i, face_point_j, face_point_k; - - face_point_i = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, iNode)); - - /// TODO: Faces may have up to 4 nodes, not all posibilities are covered - - if (iNode == 0) { - face_point_j = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, nFaceNodes-1)); - face_point_k = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, iNode+1)); - } else if (iNode == nFaceNodes-1) { - face_point_j = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, iNode-1)); - face_point_k = geometry->elem[iElem]->GetNode(geometry->elem[iElem]->GetFaces(iFace, 0)); - } - - const auto Coords_i = geometry->nodes->GetCoord(face_point_i); - const auto Coords_j = geometry->nodes->GetCoord(face_point_j); - const auto Coords_k = geometry->nodes->GetCoord(face_point_k); - - /*--- Get edge vectors from point k to i and point j to i ---*/ - su2double edgeVector_i[3], edgeVector_j[3]; - GeometryToolbox::Distance(nDim, Coords_k, Coords_i, edgeVector_i); - GeometryToolbox::Distance(nDim, Coords_j, Coords_i, edgeVector_j); - - /*--- Calculate cross product of edge vectors and its length---*/ - su2double crossProduct[3]; - GeometryToolbox::CrossProduct(edgeVector_i, edgeVector_j, crossProduct); - - /// TODO: This logic is incorrect, the norm will never be less than 0 - - crossProductLength = GeometryToolbox::Norm(nDim, crossProduct); - - /*--- Check if length is minimum or maximum ---*/ - if (crossProductLength < minCrossProductLength) { - minCrossProductLength = crossProductLength; - } else if (crossProductLength > maxCrossProductLength) { - maxCrossProductLength = crossProductLength; - } - } - - /*--- If minimum cross product length is smaller than 0, - face (and therefore element) is not convex ---*/ - if (minCrossProductLength < 0) { - nNonconvexElements++; - break; - } - - } - } + } else if (rank == MASTER_NODE) { + cout << "\nWARNING: Convexity is not checked for 3D elements (issue #1171).\n" << endl; } unsigned long nNonconvexElements_Local = nNonconvexElements; nNonconvexElements = 0; diff --git a/Common/src/wall_model.cpp b/Common/src/wall_model.cpp index 37774dbab6b..0cc34ba4bd6 100644 --- a/Common/src/wall_model.cpp +++ b/Common/src/wall_model.cpp @@ -41,7 +41,7 @@ CWallModel::CWallModel(CConfig *config) { Pr_lam = config->GetPrandtl_Lam(); Pr_turb = config->GetPrandtl_Turb(); - karman = 0.41; // von Karman constant -> k = 0.41; or 0.38; + karman = config->GetwallModelKappa(); // von Karman constant -> k = 0.41; or 0.38; } void CWallModel::WallShearStressAndHeatFlux(const su2double rhoExchange, diff --git a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp index fa11c9ee7f4..7d195d45e59 100644 --- a/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp +++ b/SU2_CFD/include/drivers/CDiscAdjMultizoneDriver.hpp @@ -98,6 +98,7 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { COutput** direct_output; /*!< \brief Array of pointers to the direct outputs. */ vector direct_nInst; /*!< \brief Total number of instances in the direct problem. */ vector nInnerIter; /*!< \brief Number of inner iterations for each zone. */ + unsigned long wrt_sol_freq = std::numeric_limits::max(); /*!< \brief File output frequency. */ su2vector Has_Deformation; /*!< \brief True if iZone has mesh deformation (used for lazy evaluation of TRANSFER tape section). */ @@ -138,6 +139,11 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { protected: + /*! + * \brief Preprocess the multizone iteration + */ + void Preprocess(unsigned long TimeIter) override; + /*! * \brief [Overload] Run an discrete adjoint update of all solvers within multiple zones. */ @@ -149,12 +155,23 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { */ bool Iterate(unsigned short iZone, unsigned long iInnerIter, bool KrylovMode = false); + /*! + * \brief Run inner iterations using a Krylov method (GMRES atm). + */ + void KrylovInnerIters(unsigned short iZone); + + /*! + * \brief Evaluate the gradient of the objective function and add to "External". + * \return "True" if the gradient is numerically 0. + */ + bool EvaluateObjectiveFunctionGradient(); + /*! * \brief Evaluate sensitivites for the current adjoint solution and output files. - * \param[in] iOuterIter - Current outer iteration. - * \param[in] StopCalc - Final iteration flag (converged or reached max number of iters). + * \param[in] Iter - Current outer or time iteration. + * \param[in] force_writing - Force file output. */ - void EvaluateSensitivities(unsigned long iOuterIter, bool StopCalc); + void EvaluateSensitivities(unsigned long Iter, bool force_writing); /*! * \brief Setup the matrix of cross-terms. Allocate necessary memory and initialize to zero. @@ -217,6 +234,11 @@ class CDiscAdjMultizoneDriver : public CMultizoneDriver { */ void Add_Solution_To_External(unsigned short iZone); + /*! + * \brief Puts dual time derivative vector to External. + */ + void Set_External_To_DualTimeDer(); + /*! * \brief Add External_Old vector to Solution. * \param[in] iZone - Zone index. diff --git a/SU2_CFD/include/drivers/CDriver.hpp b/SU2_CFD/include/drivers/CDriver.hpp index 21341a6dbe1..f6890b53a09 100644 --- a/SU2_CFD/include/drivers/CDriver.hpp +++ b/SU2_CFD/include/drivers/CDriver.hpp @@ -525,7 +525,11 @@ class CDriver { * \param[in] iVertex - Vertex identifier. * \return Unit normal (vector) at the vertex. */ - vector GetVertexUnitNormal(unsigned short iMarker, unsigned long iVertex) const; + vector GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal = false) const; + + inline vector GetVertexUnitNormal(unsigned short iMarker, unsigned long iVertex) const { + return GetVertexNormal(iMarker, iVertex, true); + } /*! * \brief Get all the boundary markers tags. @@ -661,6 +665,8 @@ class CDriver { */ void SetSourceTerm_DispAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, passivedouble val_AdjointY, passivedouble val_AdjointZ); + void SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, + passivedouble val_AdjointY, passivedouble val_AdjointZ); /*! * \brief Set the position of the heat source. diff --git a/SU2_CFD/include/interfaces/CInterface.hpp b/SU2_CFD/include/interfaces/CInterface.hpp index 0bd9e4f70fe..ea4b487cbfb 100644 --- a/SU2_CFD/include/interfaces/CInterface.hpp +++ b/SU2_CFD/include/interfaces/CInterface.hpp @@ -70,6 +70,7 @@ class CInterface { unsigned short nSpanMaxAllZones = 0; unsigned short nVar = 0; + static constexpr size_t MAXNDIM = 3; /*!< \brief Max number of space dimensions, used in some static arrays. */ public: /*! diff --git a/SU2_CFD/include/iteration/CDiscAdjFEAIteration.hpp b/SU2_CFD/include/iteration/CDiscAdjFEAIteration.hpp index 4c226c4a1f0..0170ed57496 100644 --- a/SU2_CFD/include/iteration/CDiscAdjFEAIteration.hpp +++ b/SU2_CFD/include/iteration/CDiscAdjFEAIteration.hpp @@ -86,26 +86,19 @@ class CDiscAdjFEAIteration final : public CIteration { unsigned short val_iInst) override; /*! - * \brief Perform a single iteration of the adjoint mean flow system. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration - Container vector with all the integration methods. + * \brief Perform a single iteration of the adjoint FEA problem. * \param[in] geometry - Geometrical definition of the problem. * \param[in] solver - Container vector with all the solutions. - * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement classes of the problem. - * \param[in] grid_movement - Volume grid movement classes of the problem. - * \param[in] FFDBox - FFD FFDBoxes of the problem. * \param[in] val_iZone - Index of the zone. * \param[in] val_iInst - Index of the instance. + * \param[in] CrossTerm - Boolean for CrossTerm. */ - void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, - CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, - CVolumetricMovement*** grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, - unsigned short val_iInst) override; + void IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short val_iZone, unsigned short val_iInst, bool CrossTerm) override; /*! - * \brief Monitors the convergence and other metrics for the discrete adjoint mean flow system. + * \brief Monitors the convergence and other metrics for the discrete adjoint FEA problem. * \param[in] output - Pointer to the COutput class. * \param[in] integration - Container vector with all the integration methods. * \param[in] geometry - Geometrical definition of the problem. @@ -124,12 +117,16 @@ class CDiscAdjFEAIteration final : public CIteration { unsigned short val_iInst) override; /*! - * \brief Postprocesses the discrete adjoint mean flow system before heading to another physics system or the next - * iteration. \param[in] output - Pointer to the COutput class. \param[in] integration - Container vector with all the - * integration methods. \param[in] geometry - Geometrical definition of the problem. \param[in] solver - Container - * vector with all the solutions. \param[in] numerics - Description of the numerical method (the way in which the - * equations are solved). \param[in] config - Definition of the particular problem. \param[in] surface_movement - - * Surface movement classes of the problem. \param[in] grid_movement - Volume grid movement classes of the problem. + * \brief Postprocesses the discrete adjoint FEA problem before heading to another physics system or the next + * iteration. + * \param[in] output - Pointer to the COutput class. + * \param[in] integration - Container vector with all the integration methods. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). + * \param[in] config - Definition of the particular problem. + * \param[in] surface_movement - Surface movement classes of the problem. + * \param[in] grid_movement - Volume grid movement classes of the problem. * \param[in] FFDBox - FFD FFDBoxes of the problem. * \param[in] val_iZone - Index of the zone. * \param[in] val_iInst - Index of the instance. @@ -158,9 +155,8 @@ class CDiscAdjFEAIteration final : public CIteration { * \param[in] iZone - Index of the zone. * \param[in] iInst - Index of the zone. */ - void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, unsigned short iZone, - unsigned short iInst); - using CIteration::RegisterOutput; + void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, + unsigned short iZone, unsigned short iInst) override; /*! * \brief Initializes the adjoints of the output variables of the FEM iteration. diff --git a/SU2_CFD/include/iteration/CDiscAdjFluidIteration.hpp b/SU2_CFD/include/iteration/CDiscAdjFluidIteration.hpp index 030237b926f..1e9c0666ac2 100644 --- a/SU2_CFD/include/iteration/CDiscAdjFluidIteration.hpp +++ b/SU2_CFD/include/iteration/CDiscAdjFluidIteration.hpp @@ -83,22 +83,15 @@ class CDiscAdjFluidIteration final : public CIteration { /*! * \brief Perform a single iteration of the adjoint fluid system. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration - Container vector with all the integration methods. * \param[in] geometry - Geometrical definition of the problem. * \param[in] solver - Container vector with all the solutions. - * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement classes of the problem. - * \param[in] grid_movement - Volume grid movement classes of the problem. - * \param[in] FFDBox - FFD FFDBoxes of the problem. * \param[in] val_iZone - Index of the zone. - * \param[in] val_iInst - Index of the instance + * \param[in] val_iInst - Index of the instance. + * \param[in] CrossTerm - Boolean for CrossTerm. */ - void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, - CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, - CVolumetricMovement*** grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, - unsigned short val_iInst) override; + void IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short val_iZone, unsigned short val_iInst, bool CrossTerm) override; /*! * \brief Updates the containers for the discrete adjoint fluid system. @@ -169,7 +162,7 @@ class CDiscAdjFluidIteration final : public CIteration { * \param[in] iZone - Index of the zone. * \param[in] iInst - Index of the instance. */ - void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, COutput* output, + void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, unsigned short iZone, unsigned short iInst) override; /*! diff --git a/SU2_CFD/include/iteration/CDiscAdjHeatIteration.hpp b/SU2_CFD/include/iteration/CDiscAdjHeatIteration.hpp index eef6123bf58..02268b19a4e 100644 --- a/SU2_CFD/include/iteration/CDiscAdjHeatIteration.hpp +++ b/SU2_CFD/include/iteration/CDiscAdjHeatIteration.hpp @@ -57,7 +57,7 @@ class CDiscAdjHeatIteration final : public CIteration { explicit CDiscAdjHeatIteration(const CConfig *config) : CIteration(config) {} /*! - * \brief Perform a single iteration of the adjoint fluid system. + * \brief Perform a single iteration of the adjoint heat problem. * \param[in] output - Pointer to the COutput class. * \param[in] integration - Container vector with all the integration methods. * \param[in] geometry - Geometrical definition of the problem. @@ -76,26 +76,19 @@ class CDiscAdjHeatIteration final : public CIteration { unsigned short val_iInst) override; /*! - * \brief Perform a single iteration of the adjoint fluid system. - * \param[in] output - Pointer to the COutput class. - * \param[in] integration - Container vector with all the integration methods. + * \brief Perform a single iteration of the adjoint heat problem. * \param[in] geometry - Geometrical definition of the problem. * \param[in] solver - Container vector with all the solutions. - * \param[in] numerics - Description of the numerical method (the way in which the equations are solved). * \param[in] config - Definition of the particular problem. - * \param[in] surface_movement - Surface movement classes of the problem. - * \param[in] grid_movement - Volume grid movement classes of the problem. - * \param[in] FFDBox - FFD FFDBoxes of the problem. * \param[in] val_iZone - Index of the zone. - * \param[in] val_iInst - Index of the instance layer. + * \param[in] val_iInst - Index of the instance. + * \param[in] CrossTerm - Boolean for CrossTerm. */ - void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, - CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, - CVolumetricMovement*** grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, - unsigned short val_iInst) override; + void IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short val_iZone, unsigned short val_iInst, bool CrossTerm) override; /*! - * \brief Perform a single iteration of the adjoint fluid system. + * \brief Perform a single iteration of the adjoint heat problem. * \param[in] output - Pointer to the COutput class. * \param[in] integration - Container vector with all the integration methods. * \param[in] geometry - Geometrical definition of the problem. @@ -114,7 +107,7 @@ class CDiscAdjHeatIteration final : public CIteration { unsigned short val_iInst) override; /*! - * \brief Monitors the convergence and other metrics for the discrete adjoint fluid system. + * \brief Monitors the convergence and other metrics for the discrete adjoint heat problem. */ bool Monitor(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, @@ -152,7 +145,7 @@ class CDiscAdjHeatIteration final : public CIteration { * \param[in] iZone - Index of the zone. * \param[in] val_iInst - Index of the instance layer. */ - void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, COutput* output, + void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, unsigned short iZone, unsigned short iInst) override; /*! diff --git a/SU2_CFD/include/iteration/CFEAIteration.hpp b/SU2_CFD/include/iteration/CFEAIteration.hpp index b01ef9dbea9..da1add90248 100644 --- a/SU2_CFD/include/iteration/CFEAIteration.hpp +++ b/SU2_CFD/include/iteration/CFEAIteration.hpp @@ -56,6 +56,8 @@ class CFEAIteration : public CIteration { * \param[in] surface_movement - Surface movement classes of the problem. * \param[in] grid_movement - Volume grid movement classes of the problem. * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. */ void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, diff --git a/SU2_CFD/include/iteration/CFEMFluidIteration.hpp b/SU2_CFD/include/iteration/CFEMFluidIteration.hpp index c61715e7e08..3a111035791 100644 --- a/SU2_CFD/include/iteration/CFEMFluidIteration.hpp +++ b/SU2_CFD/include/iteration/CFEMFluidIteration.hpp @@ -71,6 +71,8 @@ class CFEMFluidIteration : public CFluidIteration { * \param[in] surface_movement - Surface movement classes of the problem. * \param[in] grid_movement - Volume grid movement classes of the problem. * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. */ void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, diff --git a/SU2_CFD/include/iteration/CFluidIteration.hpp b/SU2_CFD/include/iteration/CFluidIteration.hpp index 7e9e87870e8..72979a1804f 100644 --- a/SU2_CFD/include/iteration/CFluidIteration.hpp +++ b/SU2_CFD/include/iteration/CFluidIteration.hpp @@ -63,6 +63,8 @@ class CFluidIteration : public CIteration { * \param[in] surface_movement - Surface movement classes of the problem. * \param[in] grid_movement - Volume grid movement classes of the problem. * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. */ void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, diff --git a/SU2_CFD/include/iteration/CHeatIteration.hpp b/SU2_CFD/include/iteration/CHeatIteration.hpp index 6f167b6472f..9908d439c8e 100644 --- a/SU2_CFD/include/iteration/CHeatIteration.hpp +++ b/SU2_CFD/include/iteration/CHeatIteration.hpp @@ -54,6 +54,8 @@ class CHeatIteration : public CFluidIteration { * \param[in] surface_movement - Surface movement classes of the problem. * \param[in] grid_movement - Volume grid movement classes of the problem. * \param[in] FFDBox - FFD FFDBoxes of the problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instance layer. */ void Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, diff --git a/SU2_CFD/include/iteration/CIteration.hpp b/SU2_CFD/include/iteration/CIteration.hpp index 829e501d16a..7ccdffc45d4 100644 --- a/SU2_CFD/include/iteration/CIteration.hpp +++ b/SU2_CFD/include/iteration/CIteration.hpp @@ -138,6 +138,18 @@ class CIteration { CVolumetricMovement*** grid_movement, CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst){} + /*! + * \brief A virtual member. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + * \param[in] val_iZone - Index of the zone. + * \param[in] val_iInst - Index of the instantiation. + * \param[in] CrossTerm - Boolean for CrossTerm. + */ + virtual void IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short val_iZone, unsigned short val_iInst, bool CrossTerm) {} + /*! * \brief A virtual member. * \param[in] output - Pointer to the COutput class. @@ -277,7 +289,7 @@ class CIteration { virtual void SetDependencies(CSolver***** solver, CGeometry**** geometry, CNumerics****** numerics, CConfig** config, unsigned short iZone, unsigned short iInst, RECORDING kind_recording) {} - virtual void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, COutput* output, + virtual void RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, unsigned short iZone, unsigned short iInst) {} virtual void SetRecording(CSolver***** solver, CGeometry**** geometry, CConfig** config, unsigned short val_iZone, diff --git a/SU2_CFD/include/numerics/CNumerics.hpp b/SU2_CFD/include/numerics/CNumerics.hpp index 2181487e7ac..7e5fd557df6 100644 --- a/SU2_CFD/include/numerics/CNumerics.hpp +++ b/SU2_CFD/include/numerics/CNumerics.hpp @@ -34,13 +34,8 @@ #include #include "../../../Common/include/CConfig.hpp" -#include "../fluid/CNEMOGas.hpp" -#include "../../include/fluid/CMutationTCLib.hpp" -#include "../../include/fluid/CSU2TCLib.hpp" #include "../../../Common/include/linear_algebra/blas_structure.hpp" -using namespace std; - class CElement; class CFluidModel; diff --git a/SU2_CFD/include/numerics/NEMO/CNEMONumerics.hpp b/SU2_CFD/include/numerics/NEMO/CNEMONumerics.hpp index 408a13bdbd2..ff8482d425f 100644 --- a/SU2_CFD/include/numerics/NEMO/CNEMONumerics.hpp +++ b/SU2_CFD/include/numerics/NEMO/CNEMONumerics.hpp @@ -28,6 +28,9 @@ #pragma once #include "../CNumerics.hpp" +#include "../../fluid/CNEMOGas.hpp" +#include "../../fluid/CMutationTCLib.hpp" +#include "../../fluid/CSU2TCLib.hpp" /*! * \class CNEMONumerics diff --git a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp index 9e89955793d..70106000340 100644 --- a/SU2_CFD/include/numerics/flow/flow_diffusion.hpp +++ b/SU2_CFD/include/numerics/flow/flow_diffusion.hpp @@ -73,11 +73,11 @@ class CAvgGrad_Base : public CNumerics { * This function requires that the stress tensor already be * computed using \ref GetStressTensor * - * \param[in] val_normal - Normal vector, the norm of the vector is the area of the face. - * \param[in] val_tau_wall - The wall stress + * \param[in] UnitNormal - Unit normal vector. + * \param[in] TauWall - The wall stress. */ - void AddTauWall(const su2double *val_normal, - su2double val_tau_wall); + void AddTauWall(const su2double *UnitNormal, + su2double TauWall); /** * \brief Calculate the Jacobian of the viscous + turbulent stress tensor diff --git a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp index 52aba19213c..2e0e2b8cb62 100644 --- a/SU2_CFD/include/numerics/turbulent/turb_sources.hpp +++ b/SU2_CFD/include/numerics/turbulent/turb_sources.hpp @@ -134,7 +134,8 @@ class CSourcePieceWise_TurbSA final : public CSourceBase_TurbSA { su2double dr, dg, dfw; unsigned short iDim; bool transition; - + bool axisymmetric; + public: /*! * \brief Constructor of the class. diff --git a/SU2_CFD/include/numerics_simd/CNumericsSIMD.hpp b/SU2_CFD/include/numerics_simd/CNumericsSIMD.hpp index c76d96bd373..701ee440bca 100644 --- a/SU2_CFD/include/numerics_simd/CNumericsSIMD.hpp +++ b/SU2_CFD/include/numerics_simd/CNumericsSIMD.hpp @@ -27,7 +27,6 @@ #pragma once -#include "../../../Common/include/CConfig.hpp" #include "../../../Common/include/parallelization/vectorization.hpp" /*! diff --git a/SU2_CFD/include/numerics_simd/flow/diffusion/common.hpp b/SU2_CFD/include/numerics_simd/flow/diffusion/common.hpp index 918388f4066..fa3df0f0b2f 100644 --- a/SU2_CFD/include/numerics_simd/flow/diffusion/common.hpp +++ b/SU2_CFD/include/numerics_simd/flow/diffusion/common.hpp @@ -149,6 +149,35 @@ FORCEINLINE void addQCR(const MatrixType& grad, MatrixDbl& tau) { tau(iDim,jDim) -= c_cr1 * qcr(iDim,jDim); } +/*! + * \brief Scale the stress tensor according to the target (from a + * wall function) magnitute in the tangential direction. + */ +template +FORCEINLINE void addTauWall(Int iPoint, Int jPoint, + const Container& tauWall, + const VectorDbl& unitNormal, + MatrixDbl& tau) { + + Double tauWall_i = max(gatherVariables(iPoint, tauWall), 0.0); + Double tauWall_j = max(gatherVariables(jPoint, tauWall), 0.0); + + Double isWall_i = tauWall_i > 0.0; + Double isWall_j = tauWall_j > 0.0; + /*--- Arithmetic xor. ---*/ + Double isNormalEdge = isWall_i+isWall_j - 2*isWall_i*isWall_j; + + /*--- Tau wall is 0 for edges that are not normal to walls. ---*/ + Double tauWall_ij = (tauWall_i+tauWall_j) * isNormalEdge; + + /*--- Scale is 1 for those edges, i.e. tau is not changed. ---*/ + Double scale = tauWall_ij / norm(tangentProjection(tau,unitNormal)) + (1.0-isNormalEdge); + + for (size_t iDim = 0; iDim < nDim; ++iDim) + for (size_t jDim = 0; jDim < nDim; ++jDim) + tau(iDim,jDim) *= scale; +} + /*! * \brief Jacobian of the stress tensor (compressible flow). */ diff --git a/SU2_CFD/include/numerics_simd/flow/diffusion/viscous_fluxes.hpp b/SU2_CFD/include/numerics_simd/flow/diffusion/viscous_fluxes.hpp index 6c2078bccd8..bbb9897bd7f 100644 --- a/SU2_CFD/include/numerics_simd/flow/diffusion/viscous_fluxes.hpp +++ b/SU2_CFD/include/numerics_simd/flow/diffusion/viscous_fluxes.hpp @@ -78,6 +78,7 @@ class CCompressibleViscousFluxBase : public CNumericsSIMD { const su2double cp; const bool correct; const bool useSA_QCR; + const bool wallFun; const bool uq; const bool uq_permute; const size_t uq_eigval_comp; @@ -99,6 +100,7 @@ class CCompressibleViscousFluxBase : public CNumericsSIMD { cp(gamma * gasConst / (gamma - 1)), correct(iMesh == MESH_0), useSA_QCR(config.GetQCR()), + wallFun(config.GetWall_Functions()), uq(config.GetUsing_UQ()), uq_permute(config.GetUQ_Permute()), uq_eigval_comp(config.GetEig_Val_Comp()), @@ -157,6 +159,7 @@ class CCompressibleViscousFluxBase : public CNumericsSIMD { addPerturbedRSM(avgV, avgGrad, turb_ke, tau, uq_eigval_comp, uq_permute, uq_delta_b, uq_urlx); } + if(wallFun) addTauWall(iPoint, jPoint, solution.GetTauWall(), unitNormal, tau); Double cond = derived->thermalConductivity(avgV); VectorDbl heatFlux; diff --git a/SU2_CFD/include/numerics_simd/util.hpp b/SU2_CFD/include/numerics_simd/util.hpp index 21c99c7e529..ffd5620dd39 100644 --- a/SU2_CFD/include/numerics_simd/util.hpp +++ b/SU2_CFD/include/numerics_simd/util.hpp @@ -109,6 +109,24 @@ FORCEINLINE Double squaredNorm(const VectorDbl& vector) { return squaredNorm(vector.data()); } +/*! + * \brief Tangential projection. + */ +template +FORCEINLINE VectorDbl tangentProjection(const MatrixDbl& tensor, + const VectorDbl& unitVector) { + VectorDbl proj; + for (size_t iDim = 0; iDim < nDim; ++iDim) + proj(iDim) = dot(tensor[iDim], unitVector); + + Double normalProj = dot(proj, unitVector); + + for (size_t iDim = 0; iDim < nDim; ++iDim) + proj(iDim) -= normalProj * unitVector(iDim); + + return proj; +} + /*! * \brief Vector norm. */ diff --git a/SU2_CFD/include/output/CAdjFlowOutput.hpp b/SU2_CFD/include/output/CAdjFlowCompOutput.hpp similarity index 98% rename from SU2_CFD/include/output/CAdjFlowOutput.hpp rename to SU2_CFD/include/output/CAdjFlowCompOutput.hpp index d18e6aa462c..1c6f2db616d 100644 --- a/SU2_CFD/include/output/CAdjFlowOutput.hpp +++ b/SU2_CFD/include/output/CAdjFlowCompOutput.hpp @@ -97,6 +97,6 @@ class CAdjFlowCompOutput final: public COutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CAdjFlowIncOutput.hpp b/SU2_CFD/include/output/CAdjFlowIncOutput.hpp index e4c974b68c1..02f40204347 100644 --- a/SU2_CFD/include/output/CAdjFlowIncOutput.hpp +++ b/SU2_CFD/include/output/CAdjFlowIncOutput.hpp @@ -100,6 +100,6 @@ class CAdjFlowIncOutput final: public COutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CAdjHeatOutput.hpp b/SU2_CFD/include/output/CAdjHeatOutput.hpp index 5b5586591de..2102be9ad84 100644 --- a/SU2_CFD/include/output/CAdjHeatOutput.hpp +++ b/SU2_CFD/include/output/CAdjHeatOutput.hpp @@ -1,5 +1,5 @@ /*! - * \file output_fea_discadj.hpp + * \file CAdjHeatOutput.hpp * \brief Headers of the adjoint heat output. * \author T. Albring * \version 7.1.1 "Blackbird" diff --git a/SU2_CFD/include/output/CElasticityOutput.hpp b/SU2_CFD/include/output/CElasticityOutput.hpp index b79ad3df54a..00792c68899 100644 --- a/SU2_CFD/include/output/CElasticityOutput.hpp +++ b/SU2_CFD/include/output/CElasticityOutput.hpp @@ -87,6 +87,6 @@ class CElasticityOutput final: public COutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CFVMOutput.hpp b/SU2_CFD/include/output/CFVMOutput.hpp new file mode 100644 index 00000000000..7e7da9e7a38 --- /dev/null +++ b/SU2_CFD/include/output/CFVMOutput.hpp @@ -0,0 +1,69 @@ +/*! + * \file CFVMOutput.hpp + * \brief Headers of the Finite Volume Method output. + * \author T. Kattmann + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, 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 "COutput.hpp" + +class CFVMOutput : public COutput{ +protected: + /*! + * \brief Constructor of the class + */ + CFVMOutput(CConfig *config, unsigned short nDim, bool femOutput); + + /*! + * \brief Destructor of the class. + */ + ~CFVMOutput(void) = default; + + /*! + * \brief Add Coordinates to output. + */ + void AddCoordinates(); + + /*! + * \brief Load the coordinates. + */ + template + inline void LoadCoordinates(const T& Coord, const unsigned long iPoint) { + SetVolumeOutputValue("COORD-X", iPoint, Coord[0]); + SetVolumeOutputValue("COORD-Y", iPoint, Coord[1]); + if (nDim == 3) + SetVolumeOutputValue("COORD-Z", iPoint, Coord[2]); + } + + /*! + * \brief Add common FVM outputs. + */ + void AddCommonFVMOutputs(const CConfig* config); + + /*! + * \brief Load common FVM outputs. + */ + void LoadCommonFVMOutputs(const CConfig* config, const CGeometry* geometry, unsigned long iPoint); +}; diff --git a/SU2_CFD/include/output/CFlowCompFEMOutput.hpp b/SU2_CFD/include/output/CFlowCompFEMOutput.hpp index 748be9c21a8..063cb3499f4 100644 --- a/SU2_CFD/include/output/CFlowCompFEMOutput.hpp +++ b/SU2_CFD/include/output/CFlowCompFEMOutput.hpp @@ -101,6 +101,6 @@ class CFlowCompFEMOutput final: public CFlowOutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CFlowCompOutput.hpp b/SU2_CFD/include/output/CFlowCompOutput.hpp index 7af5d70a6a6..fde484afbfd 100644 --- a/SU2_CFD/include/output/CFlowCompOutput.hpp +++ b/SU2_CFD/include/output/CFlowCompOutput.hpp @@ -40,7 +40,6 @@ class CFlowCompOutput final: public CFlowOutput { private: unsigned short turb_model; //!< Kind of turbulence model - unsigned long lastInnerIter; public: @@ -50,12 +49,6 @@ class CFlowCompOutput final: public CFlowOutput { */ CFlowCompOutput(CConfig *config, unsigned short nDim); - /*! - * \brief Destructor of the class. - */ - ~CFlowCompOutput(void) override; - - /*! * \brief Load the history output field values * \param[in] config - Definition of the particular problem. @@ -100,23 +93,17 @@ class CFlowCompOutput final: public CFlowOutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; /*! * \brief Write any additional output defined for the current solver. * \param[in] config - Definition of the particular problem per zone. */ - void SetAdditionalScreenOutput(CConfig *config) override; - - /*! - * \brief Write additional output for fixed CL mode. - * \param[in] config - Definition of the particular problem per zone. - */ - void SetFixedCLScreenOutput(CConfig *config); + void SetAdditionalScreenOutput(const CConfig *config) override; /*! * \brief Determines if the history file output. * \param[in] config - Definition of the particular problem. */ - bool WriteHistoryFile_Output(CConfig *config) override; + bool WriteHistoryFile_Output(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CFlowIncOutput.hpp b/SU2_CFD/include/output/CFlowIncOutput.hpp index af106a33093..338060bb4eb 100644 --- a/SU2_CFD/include/output/CFlowIncOutput.hpp +++ b/SU2_CFD/include/output/CFlowIncOutput.hpp @@ -1,5 +1,5 @@ -/*! - * \file CFlowIncCompOutput.hpp +/*! + * \file CFlowIncOutput.hpp * \brief Headers of the incompressible flow output. * \author T. Albring, R. Sanchez * \version 7.1.1 "Blackbird" @@ -102,6 +102,6 @@ class CFlowIncOutput final: public CFlowOutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CFlowOutput.hpp b/SU2_CFD/include/output/CFlowOutput.hpp index 8e15d607ae1..81168fb872d 100644 --- a/SU2_CFD/include/output/CFlowOutput.hpp +++ b/SU2_CFD/include/output/CFlowOutput.hpp @@ -27,23 +27,19 @@ #pragma once -#include "COutput.hpp" +#include "CFVMOutput.hpp" #include "../variables/CVariable.hpp" -class CFlowOutput : public COutput{ -public: +class CFlowOutput : public CFVMOutput{ +protected: + unsigned long lastInnerIter; + /*! * \brief Constructor of the class * \param[in] config - Definition of the particular problem. */ CFlowOutput(CConfig *config, unsigned short nDim, bool femOutput); - /*! - * \brief Destructor of the class. - */ - ~CFlowOutput(void) override; - -protected: /*! * \brief Add flow surface output fields * \param[in] config - Definition of the particular problem. @@ -104,7 +100,7 @@ class CFlowOutput : public COutput{ * \brief Write information to meta data file * \param[in] config - Definition of the particular problem per zone. */ - void WriteMetaData(CConfig *config); + void WriteMetaData(const CConfig *config); /*! * \brief Write any additional files defined for the current solver. @@ -143,13 +139,9 @@ class CFlowOutput : public COutput{ void LoadTimeAveragedData(unsigned long iPoint, CVariable *node_flow); /*! - * \brief Add common FVM outputs. - */ - void AddCommonFVMOutputs(const CConfig* config); - - /*! - * \brief Load common FVM outputs. + * \brief Write additional output for fixed CL mode. + * \param[in] config - Definition of the particular problem per zone. */ - void LoadCommonFVMOutputs(const CConfig* config, const CGeometry* geometry, unsigned long iPoint); + void SetFixedCLScreenOutput(const CConfig *config); }; diff --git a/SU2_CFD/include/output/CHeatOutput.hpp b/SU2_CFD/include/output/CHeatOutput.hpp index cb9b2b1b0f4..06f37d1a334 100644 --- a/SU2_CFD/include/output/CHeatOutput.hpp +++ b/SU2_CFD/include/output/CHeatOutput.hpp @@ -1,6 +1,6 @@ /*! * \file CHeatOutput.hpp - * \brief Headers of the heat output. + * \brief Headers of the heat output. * \author R. Sanchez, T. Albring. * \version 7.1.1 "Blackbird" * @@ -27,7 +27,7 @@ #pragma once -#include "COutput.hpp" +#include "CFVMOutput.hpp" /*! \class CHeatOutput @@ -35,7 +35,7 @@ * \author R. Sanchez, T. Albring. * \date June 5, 2018. */ -class CHeatOutput final: public COutput { +class CHeatOutput final: public CFVMOutput { public: /*! diff --git a/SU2_CFD/include/output/CMeshOutput.hpp b/SU2_CFD/include/output/CMeshOutput.hpp index 5c736090c4c..34c01ebc435 100644 --- a/SU2_CFD/include/output/CMeshOutput.hpp +++ b/SU2_CFD/include/output/CMeshOutput.hpp @@ -1,6 +1,6 @@ /*! * \file CMeshOutput.hpp - * \brief Headers of the mesh output. + * \brief Headers of the mesh output. * \author R. Sanchez, T. Albring. * \version 7.1.1 "Blackbird" * diff --git a/SU2_CFD/include/output/CMultizoneOutput.hpp b/SU2_CFD/include/output/CMultizoneOutput.hpp index 1be5ea3e753..537fc7baf61 100644 --- a/SU2_CFD/include/output/CMultizoneOutput.hpp +++ b/SU2_CFD/include/output/CMultizoneOutput.hpp @@ -1,5 +1,5 @@ /*! - * \file CDriverOutput.hpp + * \file CMultizoneOutput.hpp * \brief Headers of the main subroutines for screen and history output in multizone problems. * \author R. Sanchez, T. Albring * \version 7.1.1 "Blackbird" @@ -44,7 +44,7 @@ using namespace std; /*! - * \class CDriverOutput + * \class CMultizoneOutput * \brief Class for writing the multizone output. * \author R. Sanchez, T. Albring. */ @@ -53,7 +53,7 @@ class CMultizoneOutput final: public COutput { protected: unsigned short nZone; //!< Number of zones - string bgs_res_name; //!< Block-Gauss seidel residual name + string bgs_res_name; //!< Block-Gauss Seidel residual name bool write_zone; //!< Boolean indicating whether the individual zones write to screen public: @@ -86,17 +86,17 @@ class CMultizoneOutput final: public COutput { * \brief Determines if the history file output. * \param[in] config - Definition of the particular problem. */ - bool WriteHistoryFile_Output(CConfig *config) override; + bool WriteHistoryFile_Output(const CConfig *config) override; /*! * \brief Determines if the screen header should be written. * \param[in] config - Definition of the particular problem. */ - bool WriteScreen_Header(CConfig *config) override; + bool WriteScreen_Header(const CConfig *config) override; /*! * \brief Determines if the screen header should be written. * \param[in] config - Definition of the particular problem. */ - bool WriteScreen_Output(CConfig *config) override; + bool WriteScreen_Output(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/CNEMOCompOutput.hpp b/SU2_CFD/include/output/CNEMOCompOutput.hpp index 434536cd1c0..517c0d7be6c 100644 --- a/SU2_CFD/include/output/CNEMOCompOutput.hpp +++ b/SU2_CFD/include/output/CNEMOCompOutput.hpp @@ -41,8 +41,6 @@ class CNEMOCompOutput final: public CFlowOutput { unsigned short turb_model, /*!< \brief Kind of turbulence model */ iSpecies, /*!< \brief Species index */ nSpecies; /*!< \brief Number of species */ - unsigned long lastInnerIter; - public: /*! @@ -51,12 +49,6 @@ class CNEMOCompOutput final: public CFlowOutput { */ CNEMOCompOutput(CConfig *config, unsigned short nDim); - /*! - * \brief Destructor of the class. - */ - ~CNEMOCompOutput(void) override; - - /*! * \brief Load the history output field values * \param[in] config - Definition of the particular problem. @@ -101,23 +93,17 @@ class CNEMOCompOutput final: public CFlowOutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - bool SetInit_Residuals(CConfig *config) override; + bool SetInit_Residuals(const CConfig *config) override; /*! * \brief Write any additional output defined for the current solver. * \param[in] config - Definition of the particular problem per zone. */ - void SetAdditionalScreenOutput(CConfig *config) override; - - /*! - * \brief Write additional output for fixed CL mode. - * \param[in] config - Definition of the particular problem per zone. - */ - void SetFixedCLScreenOutput(CConfig *config); + void SetAdditionalScreenOutput(const CConfig *config) override; /*! * \brief Determines if the history file output. * \param[in] config - Definition of the particular problem. */ - bool WriteHistoryFile_Output(CConfig *config) override; + bool WriteHistoryFile_Output(const CConfig *config) override; }; diff --git a/SU2_CFD/include/output/COutput.hpp b/SU2_CFD/include/output/COutput.hpp index 08c8213aa70..403b614fc3e 100644 --- a/SU2_CFD/include/output/COutput.hpp +++ b/SU2_CFD/include/output/COutput.hpp @@ -490,26 +490,25 @@ class COutput { * \brief Set the history file header * \param[in] config - Definition of the particular problem. */ - void SetHistoryFile_Header(CConfig *config); + void SetHistoryFile_Header(const CConfig *config); /*! * \brief Write the history file output * \param[in] config - Definition of the particular problem. */ - void SetHistoryFile_Output(CConfig *config); + void SetHistoryFile_Output(const CConfig *config); /*! * \brief Write the screen header. * \param[in] config - Definition of the particular problem. */ - void SetScreen_Header(CConfig *config); - + void SetScreen_Header(const CConfig *config); /*! * \brief Write the screen output. * \param[in] config - Definition of the particular problem. */ - void SetScreen_Output(CConfig *config); + void SetScreen_Output(const CConfig *config); /*! * \brief Add a new field to the history output. @@ -691,19 +690,19 @@ class COutput { * \brief Determines if the history file output. * \param[in] config - Definition of the particular problem. */ - virtual bool WriteHistoryFile_Output(CConfig *config); + virtual bool WriteHistoryFile_Output(const CConfig *config); /*! * \brief Determines if the screen header should be written. * \param[in] config - Definition of the particular problem. */ - virtual bool WriteScreen_Header(CConfig *config); + virtual bool WriteScreen_Header(const CConfig *config); /*! * \brief Determines if the screen header should be written. * \param[in] config - Definition of the particular problem. */ - virtual bool WriteScreen_Output(CConfig *config); + virtual bool WriteScreen_Output(const CConfig *config); /*! * \brief Determines if the the volume output should be written. @@ -739,7 +738,7 @@ class COutput { * \param[in] config - Definition of the particular problem. * \return if the residuals should be initialized. */ - inline virtual bool SetInit_Residuals(CConfig *config) {return false;} + inline virtual bool SetInit_Residuals(const CConfig *config) {return false;} /*! * \brief Set the values of the volume output fields for a surface point. @@ -798,6 +797,6 @@ class COutput { * \brief Write any additional output defined for the current solver. * \param[in] config - Definition of the particular problem per zone. */ - inline virtual void SetAdditionalScreenOutput(CConfig *config){} + inline virtual void SetAdditionalScreenOutput(const CConfig *config){} }; diff --git a/SU2_CFD/include/output/COutputFactory.hpp b/SU2_CFD/include/output/COutputFactory.hpp index 3e659e97954..0aa2dd25e45 100644 --- a/SU2_CFD/include/output/COutputFactory.hpp +++ b/SU2_CFD/include/output/COutputFactory.hpp @@ -1,5 +1,5 @@ /*! - * \file COutput.hpp + * \file COutputFactory.hpp * \brief Headers of the output class. * \author T.Albring * \version 7.1.1 "Blackbird" diff --git a/SU2_CFD/include/output/COutputLegacy.hpp b/SU2_CFD/include/output/COutputLegacy.hpp index fbf334a66ca..9f34d8e4529 100644 --- a/SU2_CFD/include/output/COutputLegacy.hpp +++ b/SU2_CFD/include/output/COutputLegacy.hpp @@ -1,7 +1,7 @@ /*! - * \file output.hpp + * \file COutputLegacy.hpp * \brief Headers of the main subroutines for generating the file outputs. - * The subroutines and functions are in the output_structure.cpp file. + * The subroutines and functions are in the output_structure_legacy.cpp file. * \author F. Palacios, T. Economon, M. Colonno * \version 7.1.1 "Blackbird" * diff --git a/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp b/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp index 48c29f76dc7..750bf1dda8f 100644 --- a/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjFEASolver.hpp @@ -38,8 +38,7 @@ */ class CDiscAdjFEASolver final : public CSolver { private: - static constexpr size_t MAXNVAR = 3; /*!< \brief Max number of variables, for static arrays. */ - + static constexpr size_t MAXNVAR = 9; /*!< \brief Max number of variables, for static arrays. */ unsigned short KindDirect_Solver = 0; CSolver *direct_solver = nullptr; @@ -49,8 +48,6 @@ class CDiscAdjFEASolver final : public CSolver { struct SensData { unsigned short size = 0; su2double* val = nullptr; /*!< \brief Value of the variable. */ - int* AD_Idx = nullptr; /*!< \brief Derivative index in the AD tape. */ - bool localIdx = false; su2double* LocalSens = nullptr; /*!< \brief Local sensitivity (domain). */ su2double* GlobalSens = nullptr; /*!< \brief Global sensitivity (mpi). */ su2double* TotalSens = nullptr; /*!< \brief Total sensitivity (time domain). */ @@ -62,7 +59,6 @@ class CDiscAdjFEASolver final : public CSolver { clear(); size = n; val = new su2double[n](); - AD_Idx = new int[n](); LocalSens = new su2double[n](); GlobalSens = new su2double[n](); TotalSens = new su2double[n](); @@ -70,28 +66,18 @@ class CDiscAdjFEASolver final : public CSolver { void clear() { size = 0; - localIdx = false; delete [] val; - delete [] AD_Idx; delete [] LocalSens; delete [] GlobalSens; delete [] TotalSens; } - void Register(bool push_index) { - for (auto i = 0u; i < size; ++i) AD::RegisterInput(val[i], push_index); - } - - void SetIndex() { - for (auto i = 0u; i < size; ++i) AD::SetIndex(AD_Idx[i], val[i]); - localIdx = true; + void Register() { + for (auto i = 0u; i < size; ++i) AD::RegisterInput(val[i]); } void GetDerivative() { - if (localIdx) - for (auto i = 0u; i < size; ++i) LocalSens[i] = AD::GetDerivative(AD_Idx[i]); - else - for (auto i = 0u; i < size; ++i) LocalSens[i] = SU2_TYPE::GetDerivative(val[i]); + for (auto i = 0u; i < size; ++i) LocalSens[i] = SU2_TYPE::GetDerivative(val[i]); SU2_MPI::Allreduce(LocalSens, GlobalSens, size, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); } @@ -181,7 +167,7 @@ class CDiscAdjFEASolver final : public CSolver { * \param[in] geometry - The geometrical definition of the problem. * \param[in] config - The particular config. */ - void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config) override; + void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm) override; /*! * \brief Extract and set the geometrical sensitivity. diff --git a/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp b/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp index d7ba9d80b75..e120ed5cbf9 100644 --- a/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjMeshSolver.hpp @@ -90,7 +90,7 @@ class CDiscAdjMeshSolver final : public CSolver { * \param[in] geometry - The geometrical definition of the problem. * \param[in] config - The particular config. */ - void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config) override; + void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm) override; /*! * \brief Extract and set the geometrical sensitivity. diff --git a/SU2_CFD/include/solvers/CDiscAdjSolver.hpp b/SU2_CFD/include/solvers/CDiscAdjSolver.hpp index 8a437dfd631..82938121703 100644 --- a/SU2_CFD/include/solvers/CDiscAdjSolver.hpp +++ b/SU2_CFD/include/solvers/CDiscAdjSolver.hpp @@ -119,8 +119,9 @@ class CDiscAdjSolver final : public CSolver { * after tape has been evaluated. * \param[in] geometry - The geometrical definition of the problem. * \param[in] config - The particular config. + * \param[in] CrossTerm - Boolean for CrossTerm. */ - void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config) override; + void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm) override; /*! * \brief Set the surface sensitivity. diff --git a/SU2_CFD/include/solvers/CEulerSolver.hpp b/SU2_CFD/include/solvers/CEulerSolver.hpp index 3a181ec54de..d4a91b3d983 100644 --- a/SU2_CFD/include/solvers/CEulerSolver.hpp +++ b/SU2_CFD/include/solvers/CEulerSolver.hpp @@ -273,6 +273,11 @@ class CEulerSolver : public CFVMFlowSolverBase > CPressure; /*!< \brief Pressure coefficient for each boundary and vertex. */ vector > CPressureTarget; /*!< \brief Target Pressure coefficient for each boundary and vertex. */ vector > YPlus; /*!< \brief Yplus for each boundary and vertex. */ + vector > UTau; /*!< \brief UTau for each boundary and vertex. */ + vector > EddyViscWall; /*!< \brief Eddy viscosuty at the wall for each boundary and vertex. */ bool space_centered; /*!< \brief True if space centered scheme used. */ bool euler_implicit; /*!< \brief True if euler implicit scheme used. */ @@ -226,6 +229,13 @@ class CFVMFlowSolverBase : public CSolver { */ CFVMFlowSolverBase() : CSolver() {} + /*! + * \brief Set reference values for pressure, forces, etc., e.g. "AeroCoeffForceRef". + * \note Implement this method in the derived class and call it in its constructor. + * Duplicating this type of information has caused bugs (I know because I fixed them). + */ + virtual void SetReferenceValues(const CConfig& config) = 0; + /*! * \brief Allocate member variables. */ @@ -2443,7 +2453,7 @@ class CFVMFlowSolverBase : public CSolver { } /*! - * \brief Get the skin friction coefficient. + * \brief Get the heat flux. * \param[in] val_marker - Surface marker where the coefficient is computed. * \param[in] val_vertex - Vertex of the marker val_marker where the coefficient is evaluated. * \return Value of the heat transfer coefficient. @@ -2481,4 +2491,24 @@ class CFVMFlowSolverBase : public CSolver { inline su2double GetYPlus(unsigned short val_marker, unsigned long val_vertex) const final { return YPlus[val_marker][val_vertex]; } + + /*! + * \brief Get the u_tau . + * \param[in] val_marker - Surface marker where the coefficient is computed. + * \param[in] val_vertex - Vertex of the marker val_marker where the coefficient is evaluated. + * \return Value of the u_tau. + */ + inline su2double GetUTau(unsigned short val_marker, unsigned long val_vertex) const final { + return UTau[val_marker][val_vertex]; + } + + /*! + * \brief Get the eddy viscosity at the wall (wall functions). + * \param[in] val_marker - Surface marker where the coefficient is computed. + * \param[in] val_vertex - Vertex of the marker val_marker where the coefficient is evaluated. + * \return Value of the eddy viscosity. + */ + inline su2double GetEddyViscWall(unsigned short val_marker, unsigned long val_vertex) const final { + return EddyViscWall[val_marker][val_vertex]; + } }; diff --git a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl index fa533937244..b4dc537102d 100644 --- a/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl +++ b/SU2_CFD/include/solvers/CFVMFlowSolverBase.inl @@ -172,6 +172,14 @@ void CFVMFlowSolverBase::Allocate(const CConfig& config) { AllocVectorOfVectors(nVertex, YPlus); + /*--- U Tau in all the markers ---*/ + + AllocVectorOfVectors(nVertex, UTau); + + /*--- wall eddy viscosity in all the markers ---*/ + + AllocVectorOfVectors(nVertex, EddyViscWall); + /*--- Skin friction in all the markers ---*/ AllocVectorOfMatrices(nVertex, nDim, CSkinFriction); @@ -429,6 +437,11 @@ void CFVMFlowSolverBase::Viscous_Residual_impl(unsigned long iEdge, CGeome numerics->SetTurbKineticEnergy(turbNodes->GetSolution(iPoint,0), turbNodes->GetSolution(jPoint,0)); + /*--- Wall shear stress values (wall functions) ---*/ + + numerics->SetTauWall(nodes->GetTauWall(iPoint), + nodes->GetTauWall(jPoint)); + /*--- Compute and update residual ---*/ auto residual = numerics->ComputeResidual(config); @@ -707,7 +720,7 @@ void CFVMFlowSolverBase::LoadRestart_impl(CGeometry **geometry, CSolver ** /*--- Restart the solution from file information ---*/ - unsigned short iDim, iVar, iMesh, iMeshFine; + unsigned short iDim, iVar, iMesh; unsigned long iPoint, index, iChildren, Point_Fine; unsigned short turb_model = config->GetKind_Turb_Model(); su2double Area_Children, Area_Parent; @@ -746,6 +759,15 @@ void CFVMFlowSolverBase::LoadRestart_impl(CGeometry **geometry, CSolver ** Read_SU2_Restart_ASCII(geometry[MESH_0], config, restart_filename); } + if (update_geo && dynamic_grid) { + auto notFound = fields.end(); + if (find(fields.begin(), notFound, string("\"Grid_Velocity_x\"")) == notFound) { + if (rank == MASTER_NODE) + cout << "\nWARNING: The restart file does not contain grid velocities, these will be set to zero.\n" << endl; + steady_restart = true; + } + } + /*--- Load data from the restart into correct containers. ---*/ unsigned long counter = 0, iPoint_Global = 0; @@ -829,39 +851,22 @@ void CFVMFlowSolverBase::LoadRestart_impl(CGeometry **geometry, CSolver ** END_SU2_OMP_MASTER SU2_OMP_BARRIER - /*--- Update the geometry for flows on deforming meshes ---*/ + /*--- Update the geometry for flows on deforming meshes. ---*/ if ((dynamic_grid || static_fsi) && update_geo) { - /*--- Communicate the new coordinates and grid velocities at the halos ---*/ - - geometry[MESH_0]->InitiateComms(geometry[MESH_0], config, COORDINATES); - geometry[MESH_0]->CompleteComms(geometry[MESH_0], config, COORDINATES); + CGeometry::UpdateGeometry(geometry, config); if (dynamic_grid) { - geometry[MESH_0]->InitiateComms(geometry[MESH_0], config, GRID_VELOCITY); - geometry[MESH_0]->CompleteComms(geometry[MESH_0], config, GRID_VELOCITY); - } - - /*--- Recompute the edges and dual mesh control volumes in the - domain and on the boundaries. ---*/ - - geometry[MESH_0]->SetControlVolume(config, UPDATE); - geometry[MESH_0]->SetBoundControlVolume(config, UPDATE); - geometry[MESH_0]->SetMaxLength(config); + for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { - /*--- Update the multigrid structure after setting up the finest grid, - including computing the grid velocities on the coarser levels. ---*/ - - for (iMesh = 1; iMesh <= config->GetnMGLevels(); iMesh++) { - iMeshFine = iMesh-1; - geometry[iMesh]->SetControlVolume(config, geometry[iMeshFine], UPDATE); - geometry[iMesh]->SetBoundControlVolume(config, geometry[iMeshFine],UPDATE); - geometry[iMesh]->SetCoord(geometry[iMeshFine]); - if (dynamic_grid) { - geometry[iMesh]->SetRestricted_GridVelocity(geometry[iMeshFine], config); + /*--- Compute the grid velocities on the coarser levels. ---*/ + if (iMesh) geometry[iMesh]->SetRestricted_GridVelocity(geometry[iMesh-1], config); + else { + geometry[MESH_0]->InitiateComms(geometry[MESH_0], config, GRID_VELOCITY); + geometry[MESH_0]->CompleteComms(geometry[MESH_0], config, GRID_VELOCITY); + } } - geometry[iMesh]->SetMaxLength(config); } } @@ -973,7 +978,7 @@ void CFVMFlowSolverBase::SetInitialCondition(CGeometry **geometry, CSolver /*--- The value of the solution for the first iteration of the dual time ---*/ - if (dual_time && (TimeIter == 0 || (restart && TimeIter == config->GetRestart_Iter()))) { + if (dual_time && TimeIter == config->GetRestart_Iter()) { PushSolutionBackInTime(TimeIter, restart, rans, solver_container, geometry, config); } @@ -996,26 +1001,36 @@ void CFVMFlowSolverBase::PushSolutionBackInTime(unsigned long TimeIter, bo solver_container[iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); solver_container[iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n1(); } + + if (dynamic_grid) { + geometry[iMesh]->nodes->SetVolume_n(); + geometry[iMesh]->nodes->SetVolume_nM1(); + } + + if (config->GetGrid_Movement()) { + geometry[iMesh]->nodes->SetCoord_n(); + geometry[iMesh]->nodes->SetCoord_n1(); + } } - if (restart && (TimeIter == config->GetRestart_Iter()) && (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)) { - /*--- Load an additional restart file for a 2nd-order restart ---*/ + if (restart && (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)) { + + /*--- Load an additional restart file for a 2nd-order restart. ---*/ - solver_container[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver_container, config, config->GetRestart_Iter() - 1, - true); + solver_container[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver_container, config, TimeIter-1, true); - /*--- Load an additional restart file for the turbulence model ---*/ + /*--- Load an additional restart file for the turbulence model. ---*/ if (rans) - solver_container[MESH_0][TURB_SOL]->LoadRestart(geometry, solver_container, config, config->GetRestart_Iter() - 1, - false); + solver_container[MESH_0][TURB_SOL]->LoadRestart(geometry, solver_container, config, TimeIter-1, false); /*--- Push back this new solution to time level N. ---*/ for (unsigned short iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++) { solver_container[iMesh][FLOW_SOL]->GetNodes()->Set_Solution_time_n(); - if (rans) { - solver_container[iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); - } + if (rans) solver_container[iMesh][TURB_SOL]->GetNodes()->Set_Solution_time_n(); + + geometry[iMesh]->nodes->SetVolume_n(); + if (config->GetGrid_Movement()) geometry[iMesh]->nodes->SetCoord_n(); } } } @@ -1421,10 +1436,6 @@ void CFVMFlowSolverBase::BC_Fluid_Interface(CGeometry* geometry, visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint, 0), solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint, 0)); - /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ - - visc_numerics->SetTauWall(-1.0, -1.0); - /*--- Compute and update residual ---*/ auto residual = visc_numerics->ComputeResidual(config); @@ -1757,8 +1768,7 @@ template void CFVMFlowSolverBase::Pressure_Forces(const CGeometry* geometry, const CConfig* config) { unsigned long iVertex, iPoint; unsigned short iDim, iMarker, Boundary, Monitoring, iMarker_Monitoring; - su2double Pressure = 0.0, factor, NFPressOF, RefVel2 = 0.0, RefTemp, RefDensity = 0.0, RefPressure, Mach2Vel, - Mach_Motion; + su2double Pressure = 0.0, NFPressOF, RefPressure; const su2double *Normal = nullptr, *Coord = nullptr; string Marker_Tag, Monitoring_Tag; su2double AxiFactor; @@ -1767,49 +1777,12 @@ void CFVMFlowSolverBase::Pressure_Forces(const CGeometry* geometr su2double Beta = config->GetAoS() * PI_NUMBER / 180.0; su2double RefArea = config->GetRefArea(); su2double RefLength = config->GetRefLength(); - su2double Gas_Constant = config->GetGas_ConstantND(); auto Origin = config->GetRefOriginMoment(0); bool axisymmetric = config->GetAxisymmetric(); - /// TODO: Move these ifs to specialized functions. - - if (FlowRegime == ENUM_REGIME::COMPRESSIBLE) { - /*--- Evaluate reference values for non-dimensionalization. - For dynamic meshes, use the motion Mach number as a reference value - for computing the force coefficients. Otherwise, use the freestream values, - which is the standard convention. ---*/ - - RefTemp = Temperature_Inf; - RefDensity = Density_Inf; - if (dynamic_grid && !config->GetFSI_Simulation()) { - Mach2Vel = sqrt(Gamma * Gas_Constant * RefTemp); - Mach_Motion = config->GetMach_Motion(); - RefVel2 = (Mach_Motion * Mach2Vel) * (Mach_Motion * Mach2Vel); - } else { - RefVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) RefVel2 += Velocity_Inf[iDim] * Velocity_Inf[iDim]; - } - } + SetReferenceValues(*config); - if (FlowRegime == ENUM_REGIME::INCOMPRESSIBLE) { - /*--- Evaluate reference values for non-dimensionalization. - For dimensional or non-dim based on initial values, use - the far-field state (inf). For a custom non-dim based - on user-provided reference values, use the ref values - to compute the forces. ---*/ - - if ((config->GetRef_Inc_NonDim() == DIMENSIONAL) || (config->GetRef_Inc_NonDim() == INITIAL_VALUES)) { - RefDensity = Density_Inf; - RefVel2 = 0.0; - for (iDim = 0; iDim < nDim; iDim++) RefVel2 += Velocity_Inf[iDim] * Velocity_Inf[iDim]; - } else if (config->GetRef_Inc_NonDim() == REFERENCE_VALUES) { - RefDensity = config->GetInc_Density_Ref(); - RefVel2 = config->GetInc_Velocity_Ref() * config->GetInc_Velocity_Ref(); - } - } - - AeroCoeffForceRef = 0.5 * RefDensity * RefArea * RefVel2; - factor = 1.0 / AeroCoeffForceRef; + const su2double factor = 1.0 / AeroCoeffForceRef; /*--- Reference pressure is always the far-field value. ---*/ @@ -2451,6 +2424,7 @@ void CFVMFlowSolverBase::Friction_Forces(const CGeometry* geometr for (iMarker = 0; iMarker < nMarker; iMarker++) { + Marker_Tag = config->GetMarker_All_TagBound(iMarker); if (!config->GetViscous_Wall(iMarker)) continue; /*--- Obtain the origin for the moment computation for a particular marker ---*/ @@ -2459,7 +2433,6 @@ void CFVMFlowSolverBase::Friction_Forces(const CGeometry* geometr if (Monitoring == YES) { for (iMarker_Monitoring = 0; iMarker_Monitoring < config->GetnMarker_Monitoring(); iMarker_Monitoring++) { Monitoring_Tag = config->GetMarker_Monitoring_TagBound(iMarker_Monitoring); - Marker_Tag = config->GetMarker_All_TagBound(iMarker); if (Marker_Tag == Monitoring_Tag) Origin = config->GetRefOriginMoment(iMarker_Monitoring); } } @@ -2474,6 +2447,10 @@ void CFVMFlowSolverBase::Friction_Forces(const CGeometry* geometr su2double ForceViscous[MAXNDIM] = {0.0}, MomentViscous[MAXNDIM] = {0.0}; su2double MomentX_Force[MAXNDIM] = {0.0}, MomentY_Force[MAXNDIM] = {0.0}, MomentZ_Force[MAXNDIM] = {0.0}; + /* --- check if wall functions are used --- */ + + const bool wallfunctions = (config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE); + /*--- Loop over the vertices to compute the forces ---*/ for (iVertex = 0; iVertex < geometry->nVertex[iMarker]; iVertex++) { @@ -2537,7 +2514,12 @@ void CFVMFlowSolverBase::Friction_Forces(const CGeometry* geometr WallShearStress[iMarker][iVertex] = 0.0; for (iDim = 0; iDim < nDim; iDim++) { TauTangent[iDim] = TauElem[iDim] - TauNormal * UnitNormal[iDim]; - CSkinFriction[iMarker](iVertex,iDim) = TauTangent[iDim] * factorFric; + /* --- in case of wall functions, we have computed the skin friction in the turbulence solver --- */ + /* --- Note that in the wall model, we switch off the computation when the computed y+ < 5 --- */ + /* --- We put YPlus to 1.0 so we have to compute skinfriction and the actual y+ in that case as well --- */ + if (!wallfunctions || (wallfunctions && YPlus[iMarker][iVertex] < 5.0)) + CSkinFriction[iMarker](iVertex,iDim) = TauTangent[iDim] * factorFric; + WallShearStress[iMarker][iVertex] += TauTangent[iDim] * TauTangent[iDim]; } WallShearStress[iMarker][iVertex] = sqrt(WallShearStress[iMarker][iVertex]); @@ -2550,7 +2532,11 @@ void CFVMFlowSolverBase::Friction_Forces(const CGeometry* geometr /*--- Compute y+ and non-dimensional velocity ---*/ FrictionVel = sqrt(fabs(WallShearStress[iMarker][iVertex]) / Density); - YPlus[iMarker][iVertex] = WallDistMod * FrictionVel / (Viscosity / Density); + + /* --- in case of wall functions, we have computed YPlus in the turbulence class --- */ + /* --- Note that we do not recompute y+ when y+<5 because y+ can become > 5 again --- */ + if (!wallfunctions) + YPlus[iMarker][iVertex] = WallDistMod * FrictionVel / (Viscosity / Density); /*--- Compute total and maximum heat flux on the wall ---*/ diff --git a/SU2_CFD/include/solvers/CIncEulerSolver.hpp b/SU2_CFD/include/solvers/CIncEulerSolver.hpp index aa925f387d1..710ab4dd742 100644 --- a/SU2_CFD/include/solvers/CIncEulerSolver.hpp +++ b/SU2_CFD/include/solvers/CIncEulerSolver.hpp @@ -119,6 +119,11 @@ class CIncEulerSolver : public CFVMFlowSolverBase void Explicit_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iRKStep); + /*! + * \brief Set reference values for pressure, forces, etc. + */ + void SetReferenceValues(const CConfig& config) final; + public: /*! * \brief Constructor of the class. diff --git a/SU2_CFD/include/solvers/CIncNSSolver.hpp b/SU2_CFD/include/solvers/CIncNSSolver.hpp index a447a101e71..8702dada838 100644 --- a/SU2_CFD/include/solvers/CIncNSSolver.hpp +++ b/SU2_CFD/include/solvers/CIncNSSolver.hpp @@ -65,6 +65,16 @@ class CIncNSSolver final : public CIncEulerSolver { void Viscous_Residual(unsigned long iEdge, CGeometry *geometry, CSolver **solver_container, CNumerics *numerics, CConfig *config) override; +/*! + * \brief Computes the wall shear stress (Tau_Wall) on the surface using a wall function. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] config - Definition of the particular problem. + */ + void SetTauWall_WF(CGeometry *geometry, + CSolver** solver_container, + const CConfig* config); + /*! * \brief Compute necessary quantities (massflow, integrated heatflux, avg density) * for streamwise periodic cases. Also sets new delta P for prescribed massflow. diff --git a/SU2_CFD/include/solvers/CMeshSolver.hpp b/SU2_CFD/include/solvers/CMeshSolver.hpp index 2b8cdb04b9e..712619cddbe 100644 --- a/SU2_CFD/include/solvers/CMeshSolver.hpp +++ b/SU2_CFD/include/solvers/CMeshSolver.hpp @@ -72,21 +72,14 @@ class CMeshSolver final : public CFEASolver { * \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. - * \param[in] config - Definition of the particular problem. - */ - void UpdateDualGrid(CGeometry *geometry, CConfig *config); + void UpdateGridCoord(CGeometry *geometry, const CConfig *config); /*! * \brief Compute the grid velocity form the displacements of the mesh. * \param[in] geometry - Geometrical definition of the problem. * \param[in] config - Definition of the particular problem. */ - void ComputeGridVelocity(CGeometry *geometry, CConfig *config); + void ComputeGridVelocity(CGeometry **geometry, const CConfig *config) const; /*! * \brief Compute the grid velocity form the velocity at deformable boundary. @@ -96,13 +89,6 @@ class CMeshSolver final : public CFEASolver { */ void ComputeGridVelocity_FromBoundary(CGeometry **geometry, CNumerics **numerics, CConfig *config); - /*! - * \brief Update the coarse multigrid levels after the grid movement. - * \param[in] geometry - Geometrical definition of the problem. - * \param[in] config - Definition of the particular problem. - */ - void UpdateMultiGrid(CGeometry **geometry, CConfig *config) const; - /*! * \brief Check the boundary vertex that are going to be moved. * \param[in] geometry - Geometrical definition of the problem. @@ -120,6 +106,12 @@ class CMeshSolver final : public CFEASolver { */ void BC_Deforming(CGeometry *geometry, const CConfig *config, unsigned short val_marker, bool velocity); + /*! + * \brief Load the geometries at the previous time states n and nM1. + * \param[in] geometry - Geometrical definition of the problem. + */ + void RestartOldGeometry(CGeometry *geometry, const CConfig *config); + public: /*! * \brief Constructor of the class. @@ -183,12 +175,6 @@ class CMeshSolver final : public CFEASolver { int val_iter, bool val_update_geo) override; - /*! - * \brief Load the geometries at the previous time states n and nM1. - * \param[in] geometry - Geometrical definition of the problem. - */ - void Restart_OldGeometry(CGeometry *geometry, CConfig *config) override; - /*! * \brief Get minimun volume in the mesh * \return diff --git a/SU2_CFD/include/solvers/CNEMOEulerSolver.hpp b/SU2_CFD/include/solvers/CNEMOEulerSolver.hpp index 9f977e61165..569d25464aa 100644 --- a/SU2_CFD/include/solvers/CNEMOEulerSolver.hpp +++ b/SU2_CFD/include/solvers/CNEMOEulerSolver.hpp @@ -85,6 +85,11 @@ class CNEMOEulerSolver : public CFVMFlowSolverBaseval_marker where the coefficient is evaluated. + * \return Value of the u tau. + */ + inline virtual su2double GetUTau(unsigned short val_marker, unsigned long val_vertex) const { return 0; } + + /*! + * \brief A virtual member. + * \param[in] val_marker - Surface marker where the coefficient is computed. + * \param[in] val_vertex - Vertex of the marker val_marker where the coefficient is evaluated. + * \return Value of the eddy viscosity. + */ + inline virtual su2double GetEddyViscWall(unsigned short val_marker, unsigned long val_vertex) const { return 0; } + /*! * \brief A virtual member. * \return Value of the StrainMag_Max @@ -3617,8 +3633,9 @@ class CSolver { * \param[in] geometry - The geometrical definition of the problem. * \param[in] solver_container - The solver container holding all solutions. * \param[in] config - The particular config. + * \param[in] CrossTerm - Boolean to determine if this is a cross term extraction. */ - inline virtual void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config){} + inline virtual void ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm){} /*! * \brief A virtual member. diff --git a/SU2_CFD/include/solvers/CTurbSASolver.hpp b/SU2_CFD/include/solvers/CTurbSASolver.hpp index 9ebaae737c6..41b82b4486e 100644 --- a/SU2_CFD/include/solvers/CTurbSASolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSASolver.hpp @@ -60,10 +60,8 @@ class CTurbSASolver final : public CTurbSolver { * \param[in] config - Definition of the particular problem. * \param[in] val_marker - Surface marker where the boundary condition is applied. */ - void SetNuTilde_WF(CGeometry *geometry, + void SetTurbVars_WF(CGeometry *geometry, CSolver **solver_container, - CNumerics *conv_numerics, - CNumerics *visc_numerics, const CConfig *config, unsigned short val_marker); diff --git a/SU2_CFD/include/solvers/CTurbSSTSolver.hpp b/SU2_CFD/include/solvers/CTurbSSTSolver.hpp index 323f0a2542c..d00ce5c6d00 100644 --- a/SU2_CFD/include/solvers/CTurbSSTSolver.hpp +++ b/SU2_CFD/include/solvers/CTurbSSTSolver.hpp @@ -40,6 +40,23 @@ class CTurbSSTSolver final : public CTurbSolver { su2double constants[10] = {0.0}; /*!< \brief Constants for the model. */ + + + /*! + * \brief Compute nu tilde from the wall functions. + * \param[in] geometry - Geometrical definition of the problem. + * \param[in] solver_container - Container vector with all the solutions. + * \param[in] conv_numerics - Description of the numerical method. + * \param[in] visc_numerics - Description of the numerical method. + * \param[in] config - Definition of the particular problem. + * \param[in] val_marker - Surface marker where the boundary condition is applied. + */ + void SetTurbVars_WF(CGeometry *geometry, + CSolver **solver_container, + const CConfig *config, + unsigned short val_marker); + + public: /*! * \brief Constructor of the class. @@ -281,4 +298,5 @@ class CTurbSSTSolver final : public CTurbSolver { */ inline su2double GetOmega_Inf(void) const override { return Solution_Inf[1]; } + }; diff --git a/SU2_CFD/include/variables/CDiscAdjFEABoundVariable.hpp b/SU2_CFD/include/variables/CDiscAdjFEABoundVariable.hpp index f0e6d9a23b5..955b5a04d16 100644 --- a/SU2_CFD/include/variables/CDiscAdjFEABoundVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjFEABoundVariable.hpp @@ -27,7 +27,7 @@ #pragma once -#include "CDiscAdjFEAVariable.hpp" +#include "CDiscAdjVariable.hpp" #include "../../../Common/include/containers/CVertexMap.hpp" /*! @@ -37,29 +37,27 @@ * \author R. Sanchez. * \version 7.1.1 "Blackbird" */ -class CDiscAdjFEABoundVariable final : public CDiscAdjFEAVariable { +class CDiscAdjFEABoundVariable final : public CDiscAdjVariable { private: MatrixType FlowTraction_Sens; /*!< \brief Adjoint of the flow tractions. */ MatrixType SourceTerm_DispAdjoint; /*!< \brief Source term applied into the displacement adjoint coming from external solvers. */ + MatrixType SourceTerm_VelAdjoint; CVertexMap VertexMap; /*!< \brief Object that controls accesses to the variables of this class. */ public: /*! * \overload - * \param[in] disp - Pointer to the adjoint value (initialization value). - * \param[in] vel - Pointer to the adjoint value (initialization value). - * \param[in] accel - Pointer to the adjoint value (initialization value). + * \param[in] sol - Pointer to the adjoint value (initialization value). * \param[in] npoint - Number of points/nodes/vertices in the domain. * \param[in] ndim - Number of dimensions of the problem. * \param[in] nvar - Number of variables of the problem. - * \param[in] unsteady - Allocate velocity and acceleration. * \param[in] config - Definition of the particular problem. */ - CDiscAdjFEABoundVariable(const su2double *disp, const su2double *vel, const su2double *accel, - unsigned long npoint, unsigned long ndim, unsigned long nvar, bool unsteady, CConfig *config); + CDiscAdjFEABoundVariable(const su2double *sol, unsigned long npoint, unsigned long ndim, + unsigned long nvar, CConfig *config); /*! * \brief Destructor of the class. @@ -101,6 +99,10 @@ class CDiscAdjFEABoundVariable final : public CDiscAdjFEAVariable { if (!VertexMap.GetVertexIndex(iPoint)) return; SourceTerm_DispAdjoint(iPoint,iDim) = val; } + inline void SetSourceTerm_VelAdjoint(unsigned long iPoint, unsigned long iDim, su2double val) override { + if (!VertexMap.GetVertexIndex(iPoint)) return; + SourceTerm_VelAdjoint(iPoint,iDim) = val; + } /*! * \brief Get the source term applied into the displacement adjoint coming from external solvers @@ -111,6 +113,10 @@ class CDiscAdjFEABoundVariable final : public CDiscAdjFEAVariable { if (!VertexMap.GetVertexIndex(iPoint)) return 0.0; return SourceTerm_DispAdjoint(iPoint,iDim); } + inline su2double GetSourceTerm_VelAdjoint(unsigned long iPoint, unsigned long iDim) const override { + if (!VertexMap.GetVertexIndex(iPoint)) return 0.0; + return SourceTerm_VelAdjoint(iPoint,iDim); + } /*! * \brief Get whether a node is on the boundary diff --git a/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp b/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp deleted file mode 100644 index c9ce1e723a6..00000000000 --- a/SU2_CFD/include/variables/CDiscAdjFEAVariable.hpp +++ /dev/null @@ -1,238 +0,0 @@ -/*! - * \file CDiscAdjFEAVariable.hpp - * \brief Main class for defining the variables of the adjoint FEA solver. - * \author T. Albring, R. Sanchez. - * \version 7.1.1 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2021, 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 "CVariable.hpp" - -/*! - * \class CDiscAdjFEAVariable - * \brief Main class for defining the variables of the adjoint solver. - * \ingroup Discrete_Adjoint - * \author T. Albring, R. Sanchez. - * \version 7.1.1 "Blackbird" - */ -class CDiscAdjFEAVariable : public CVariable { -protected: - MatrixType Sensitivity; /* Vector holding the derivative of target functional with respect to the coordinates at this node*/ - MatrixType Solution_Direct; - - MatrixType Dynamic_Derivative; - MatrixType Dynamic_Derivative_n; - MatrixType Dynamic_Derivative_Vel; - MatrixType Dynamic_Derivative_Vel_n; - MatrixType Dynamic_Derivative_Accel; - MatrixType Dynamic_Derivative_Accel_n; - - MatrixType Solution_Vel; - MatrixType Solution_Accel; - - MatrixType Solution_Vel_time_n; - MatrixType Solution_Accel_time_n; - - MatrixType Solution_Old_Vel; - MatrixType Solution_Old_Accel; - - MatrixType Solution_Direct_Vel; - MatrixType Solution_Direct_Accel; - - /*! - * \brief Constructor of the class. - * \param[in] disp - Pointer to the adjoint value (initialization value). - * \param[in] vel - Pointer to the adjoint value (initialization value). - * \param[in] accel - Pointer to the adjoint value (initialization value). - * \param[in] npoint - Number of points/nodes/vertices in the domain. - * \param[in] ndim - Number of dimensions of the problem. - * \param[in] nvar - Number of variables of the problem. - * \param[in] unsteady - Allocate velocity and acceleration. - * \param[in] config - Definition of the particular problem. - */ - CDiscAdjFEAVariable(const su2double *disp, const su2double *vel, const su2double *accel, - unsigned long npoint, unsigned long ndim, unsigned long nvar, bool unsteady, CConfig *config); - -public: - /*! - * \brief Destructor of the class. - */ - ~CDiscAdjFEAVariable() override = default; - - /*! - * \brief Set the sensitivity at the node - * \param[in] iDim - spacial component - * \param[in] val - value of the Sensitivity - */ - inline void SetSensitivity(unsigned long iPoint, unsigned long iDim, su2double val) final { Sensitivity(iPoint,iDim) = val; } - - /*! - * \brief Get the Sensitivity at the node - * \param[in] iDim - spacial component - * \return value of the Sensitivity - */ - inline su2double GetSensitivity(unsigned long iPoint, unsigned long iDim) const final { return Sensitivity(iPoint,iDim);} - - inline void SetDynamic_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) final { - Dynamic_Derivative(iPoint,iVar) = der; - } - - inline void SetDynamic_Derivative_n(unsigned long iPoint, unsigned long iVar, su2double der) final { - Dynamic_Derivative_n(iPoint,iVar) = der; - } - - inline su2double GetDynamic_Derivative(unsigned long iPoint, unsigned long iVar) const final { - return Dynamic_Derivative(iPoint,iVar); - } - - inline su2double GetDynamic_Derivative_n(unsigned long iPoint, unsigned long iVar) const final { - return Dynamic_Derivative_n(iPoint,iVar); - } - - inline void SetDynamic_Derivative_Vel(unsigned long iPoint, unsigned long iVar, su2double der) final { - Dynamic_Derivative_Vel(iPoint,iVar) = der; - } - - inline void SetDynamic_Derivative_Vel_n(unsigned long iPoint, unsigned long iVar, su2double der) final { - Dynamic_Derivative_Vel_n(iPoint,iVar) = der; - } - - inline su2double GetDynamic_Derivative_Vel(unsigned long iPoint, unsigned long iVar) const final { - return Dynamic_Derivative_Vel(iPoint,iVar); - } - - inline su2double GetDynamic_Derivative_Vel_n(unsigned long iPoint, unsigned long iVar) const final { - return Dynamic_Derivative_Vel_n(iPoint,iVar); - } - - inline void SetDynamic_Derivative_Accel(unsigned long iPoint, unsigned long iVar, su2double der) final { - Dynamic_Derivative_Accel(iPoint,iVar) = der; - } - - inline void SetDynamic_Derivative_Accel_n(unsigned long iPoint, unsigned long iVar, su2double der) final { - Dynamic_Derivative_Accel_n(iPoint,iVar) = der; - } - - inline su2double GetDynamic_Derivative_Accel(unsigned long iPoint, unsigned long iVar) const final { - return Dynamic_Derivative_Accel(iPoint,iVar); - } - - inline su2double GetDynamic_Derivative_Accel_n(unsigned long iPoint, unsigned long iVar) const final { - return Dynamic_Derivative_Accel_n(iPoint,iVar); - } - - inline void SetSolution_Direct(unsigned long iPoint, const su2double *val_solution_direct) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Direct(iPoint,iVar) = val_solution_direct[iVar]; - } - - inline void SetSolution_Vel_Direct(unsigned long iPoint, const su2double *val_solution_direct) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Direct_Vel(iPoint,iVar) = val_solution_direct[iVar]; - } - - inline void SetSolution_Accel_Direct(unsigned long iPoint, const su2double *val_solution_direct) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Direct_Accel(iPoint,iVar) = val_solution_direct[iVar]; - } - - inline su2double* GetSolution_Direct(unsigned long iPoint) final { return Solution_Direct[iPoint]; } - - inline su2double* GetSolution_Vel_Direct(unsigned long iPoint) final { return Solution_Direct_Vel[iPoint]; } - - inline su2double* GetSolution_Accel_Direct(unsigned long iPoint) final { return Solution_Direct_Accel[iPoint]; } - - inline su2double GetSolution_Old_Vel(unsigned long iPoint, unsigned long iVar) const final { return Solution_Old_Vel(iPoint,iVar); } - - inline su2double GetSolution_Old_Accel(unsigned long iPoint, unsigned long iVar) const final { return Solution_Old_Accel(iPoint,iVar); } - - /*! - * \brief Get the acceleration (Structural Analysis). - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline su2double GetSolution_Accel(unsigned long iPoint, unsigned long iVar) const final { return Solution_Accel(iPoint,iVar); } - - /*! - * \brief Get the acceleration of the nodes (Structural Analysis) at time n. - * \param[in] iVar - Index of the variable. - * \return Pointer to the old solution vector. - */ - inline su2double GetSolution_Accel_time_n(unsigned long iPoint, unsigned long iVar) const final { return Solution_Accel_time_n(iPoint,iVar); } - - /*! - * \brief Get the velocity (Structural Analysis). - * \param[in] iVar - Index of the variable. - * \return Value of the solution for the index iVar. - */ - inline su2double GetSolution_Vel(unsigned long iPoint, unsigned long iVar) const final { return Solution_Vel(iPoint,iVar); } - - /*! - * \brief Get the velocity of the nodes (Structural Analysis) at time n. - * \param[in] iVar - Index of the variable. - * \return Pointer to the old solution vector. - */ - inline su2double GetSolution_Vel_time_n(unsigned long iPoint, unsigned long iVar) const final { return Solution_Vel_time_n(iPoint,iVar); } - - /*! - * \brief Set the value of the acceleration (Structural Analysis - adjoint). - * \param[in] val_solution - Solution of the problem (acceleration). - */ - inline void SetSolution_Accel(unsigned long iPoint, const su2double *val_solution_accel) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - Solution_Accel(iPoint,iVar) = val_solution_accel[iVar]; - } - - /*! - * \brief Set the value of the velocity (Structural Analysis - adjoint). - * \param[in] val_solution - Solution of the problem (velocity). - */ - inline void SetSolution_Vel(unsigned long iPoint, const su2double *val_solution_vel) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Vel(iPoint,iVar) = val_solution_vel[iVar]; - } - - /*! - * \brief Set the value of the adjoint acceleration (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - inline void SetSolution_Accel_time_n(unsigned long iPoint, const su2double *val_solution_accel_time_n) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Accel_time_n(iPoint,iVar) = val_solution_accel_time_n[iVar]; - } - - /*! - * \brief Set the value of the adjoint velocity (Structural Analysis) at time n. - * \param[in] val_solution_old - Pointer to the residual vector. - */ - inline void SetSolution_Vel_time_n(unsigned long iPoint, const su2double *val_solution_vel_time_n) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Vel_time_n(iPoint,iVar) = val_solution_vel_time_n[iVar]; - } - - /*! - * \brief Set the value of the old acceleration (Structural Analysis - adjoint). - */ - void Set_OldSolution_Accel() final; - - /*! - * \brief Set the value of the old velocity (Structural Analysis - adjoint). - */ - void Set_OldSolution_Vel() final; - -}; diff --git a/SU2_CFD/include/variables/CDiscAdjVariable.hpp b/SU2_CFD/include/variables/CDiscAdjVariable.hpp index 65c27eed918..51a9a9a2812 100644 --- a/SU2_CFD/include/variables/CDiscAdjVariable.hpp +++ b/SU2_CFD/include/variables/CDiscAdjVariable.hpp @@ -35,18 +35,12 @@ * \ingroup Discrete_Adjoint * \author T. Albring. */ -class CDiscAdjVariable final : public CVariable { +class CDiscAdjVariable : public CVariable { private: - MatrixType Sensitivity; /* Vector holding the derivative of target functional with respect to the coordinates at this node*/ - MatrixType Solution_Direct; - MatrixType DualTime_Derivative; - MatrixType DualTime_Derivative_n; - - MatrixType Solution_Geometry; - MatrixType Solution_Geometry_Old; - MatrixType Geometry_Direct; - - MatrixType Solution_Geometry_BGS_k; + MatrixType Sensitivity; /*!< \brief Vector holding the derivative of target functional with respect to the coordinates at this node. */ + MatrixType Solution_Direct; /*!< \brief Stores the primal solution of the current timestep in order to be able to reset. */ + MatrixType DualTime_Derivative; /*!< \brief Container holding all/sum-of dual time contributions to the adjoint variable. */ + MatrixType DualTime_Derivative_n; /*!< \brief Container holding dual time contributions to the adjoint variable used in the next timestep. */ public: /*! @@ -66,89 +60,66 @@ class CDiscAdjVariable final : public CVariable { /*! * \brief Set the sensitivity at the node - * \param[in] iDim - spacial component - * \param[in] val - value of the Sensitivity */ - inline void SetSensitivity(unsigned long iPoint, unsigned long iDim, su2double val) override { Sensitivity(iPoint,iDim) = val;} + inline void SetSensitivity(unsigned long iPoint, unsigned long iDim, su2double val) final { + Sensitivity(iPoint,iDim) = val; + } /*! * \brief Get the Sensitivity at the node - * \param[in] iDim - spacial component - * \return value of the Sensitivity */ - inline su2double GetSensitivity(unsigned long iPoint, unsigned long iDim) const override { return Sensitivity(iPoint,iDim); } - - inline void SetDual_Time_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) override { DualTime_Derivative(iPoint,iVar) = der; } - - inline void SetDual_Time_Derivative_n(unsigned long iPoint, unsigned long iVar, su2double der) override { DualTime_Derivative_n(iPoint,iVar) = der; } - - inline su2double GetDual_Time_Derivative(unsigned long iPoint, unsigned long iVar) const override { return DualTime_Derivative(iPoint,iVar); } - - inline su2double GetDual_Time_Derivative_n(unsigned long iPoint, unsigned long iVar) const override { return DualTime_Derivative_n(iPoint,iVar); } - - inline void SetSolution_Direct(unsigned long iPoint, const su2double *val_solution_direct) override { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - Solution_Direct(iPoint,iVar) = val_solution_direct[iVar]; + inline su2double GetSensitivity(unsigned long iPoint, unsigned long iDim) const final { + return Sensitivity(iPoint,iDim); } - inline su2double* GetSolution_Direct(unsigned long iPoint) override { return Solution_Direct[iPoint]; } - /*! - * \brief Set the restart geometry (coordinate of the converged solution) - * \param[in] val_geometry_direct - Value of the restart coordinate. + * \brief Set/store the dual time contributions to the adjoint variable. + * Contains sum of contributions from 2 timesteps for dual time 2nd order. */ - inline void SetGeometry_Direct(unsigned long iPoint, const su2double *val_geometry_direct) override { - for (unsigned long iDim = 0; iDim < nDim; iDim++) - Geometry_Direct(iPoint,iDim) = val_geometry_direct[iDim]; + inline void SetDual_Time_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) { + DualTime_Derivative(iPoint,iVar) = der; } /*! - * \brief Get the restart geometry (coordinate of the converged solution). - * \return Pointer to the restart coordinate vector. + * \brief Set/store the dual time contributions to the adjoint variable for upcoming timestep. */ - inline su2double *GetGeometry_Direct(unsigned long iPoint) override { return Geometry_Direct[iPoint]; } - - /*! - * \brief Get the restart geometry (coordinate of the converged solution). - * \return Coordinate iDim of the geometry_direct vector. - */ - inline su2double GetGeometry_Direct(unsigned long iPoint, unsigned long iDim) const override { return Geometry_Direct(iPoint,iDim); } + inline void SetDual_Time_Derivative_n(unsigned long iPoint, unsigned long iVar, su2double der) { + DualTime_Derivative_n(iPoint,iVar) = der; + } /*! - * \brief Get the geometry solution. - * \param[in] iDim - Index of the coordinate. - * \return Value of the solution for the index iDim. + * \brief Return the dual time contributions to the adjoint variable. + * Contains sum of contributions from 2 timesteps for dual time 2nd order. */ - inline su2double GetSolution_Geometry(unsigned long iPoint, unsigned long iDim) const override { return Solution_Geometry(iPoint,iDim); } + inline su2double GetDual_Time_Derivative(unsigned long iPoint, unsigned long iVar) const { + return DualTime_Derivative(iPoint,iVar); + } /*! - * \brief Set the value of the mesh solution (adjoint). - * \param[in] val_solution_geometry - Solution of the problem (acceleration). + * \brief Return the dual time contributions to the adjoint variable for upcoming timestep. */ - inline void SetSolution_Geometry(unsigned long iPoint, const su2double *val_solution_geometry) override { - for (unsigned long iDim = 0; iDim < nDim; iDim++) - Solution_Geometry(iPoint,iDim) = val_solution_geometry[iDim]; + inline su2double GetDual_Time_Derivative_n(unsigned long iPoint, unsigned long iVar) const { + return DualTime_Derivative_n(iPoint,iVar); } /*! - * \brief A virtual member. Set the value of the mesh solution (adjoint). - * \param[in] val_solution_geometry - Solution of the problem (acceleration). + * \brief Set/store the primal solution for all variables of one point. */ - inline void SetSolution_Geometry(unsigned long iPoint, unsigned long iVar, su2double val_solution_geometry) override { - Solution_Geometry(iPoint,iVar) = val_solution_geometry; + inline void SetSolution_Direct(unsigned long iPoint, const su2double *val_solution_direct) final { + for (unsigned long iVar = 0; iVar < nVar; iVar++) + Solution_Direct(iPoint,iVar) = val_solution_direct[iVar]; } /*! - * \brief Set the value of the mesh solution (adjoint). + * \brief Returns the primal solution for all variables of one point. */ - void Set_OldSolution_Geometry() override; + inline su2double* GetSolution_Direct(unsigned long iPoint) final { + return Solution_Direct[iPoint]; + } /*! - * \brief Get the value of the old geometry solution (adjoint). - * \param[out] val_solution - old adjoint solution for coordinate iDim + * \brief Set Dual-time derivative contributions to the external. */ - inline su2double Get_OldSolution_Geometry(unsigned long iPoint, unsigned long iDim) const override { - return Solution_Geometry_Old(iPoint,iDim); - } + void Set_External_To_DualTimeDer() final; }; diff --git a/SU2_CFD/include/variables/CFEAVariable.hpp b/SU2_CFD/include/variables/CFEAVariable.hpp index 5452bf2de63..975f4b24f56 100644 --- a/SU2_CFD/include/variables/CFEAVariable.hpp +++ b/SU2_CFD/include/variables/CFEAVariable.hpp @@ -45,12 +45,6 @@ class CFEAVariable : public CVariable { VectorType VonMises_Stress; /*!< \brief Von Mises stress. */ - MatrixType Solution_Vel; /*!< \brief Velocity of the nodes. */ - MatrixType Solution_Vel_time_n; /*!< \brief Velocity of the nodes at time n. */ - - MatrixType Solution_Accel; /*!< \brief Acceleration of the nodes. */ - MatrixType Solution_Accel_time_n; /*!< \brief Acceleration of the nodes at time n. */ - MatrixType Solution_Pred; /*!< \brief Predictor of the solution for FSI purposes */ MatrixType Solution_Pred_Old; /*!< \brief Predictor of the solution at time n for FSI purposes */ MatrixType Solution_Vel_Pred; /*!< \brief Predictor of the velocity solution for FSI purposes */ @@ -59,6 +53,34 @@ class CFEAVariable : public CVariable { MatrixType Prestretch; /*!< \brief Prestretch geometry */ + /*! + * \brief Wrappers to solution to access velocity and acceleration by name. + */ + FORCEINLINE su2double& Solution_Vel(unsigned long iPoint, unsigned long iVar) { + return Solution(iPoint,iVar+nVar); + } + FORCEINLINE const su2double& Solution_Vel(unsigned long iPoint, unsigned long iVar) const { + return Solution(iPoint,iVar+nVar); + } + FORCEINLINE su2double& Solution_Accel(unsigned long iPoint, unsigned long iVar) { + return Solution(iPoint,iVar+2*nVar); + } + FORCEINLINE const su2double& Solution_Accel(unsigned long iPoint, unsigned long iVar) const { + return Solution(iPoint,iVar+2*nVar); + } + FORCEINLINE su2double& Solution_Vel_time_n(unsigned long iPoint, unsigned long iVar) { + return Solution_time_n(iPoint,iVar+nVar); + } + FORCEINLINE const su2double& Solution_Vel_time_n(unsigned long iPoint, unsigned long iVar) const { + return Solution_time_n(iPoint,iVar+nVar); + } + FORCEINLINE su2double& Solution_Accel_time_n(unsigned long iPoint, unsigned long iVar) { + return Solution_time_n(iPoint,iVar+2*nVar); + } + FORCEINLINE const su2double& Solution_Accel_time_n(unsigned long iPoint, unsigned long iVar) const { + return Solution_time_n(iPoint,iVar+2*nVar); + } + /*! * \brief Constructor of the class. * \note This class is not supposed to be instantiated, it is only a building block for CFEABoundVariable @@ -133,12 +155,6 @@ class CFEAVariable : public CVariable { Solution_Vel(iPoint,iVar) = val_solution_vel; } - /*! - * \brief Set the value of the velocity (Structural Analysis) at time n. - * \param[in] val_solution - Solution of the problem (acceleration). - */ - void SetSolution_Vel_time_n() final; - /*! * \brief Set the value of the velocity (Structural Analysis) at time n. * \param[in] val_solution_vel_time_n - Pointer to the residual vector. @@ -167,7 +183,7 @@ class CFEAVariable : public CVariable { * \brief Get the solution of the problem. * \return Pointer to the solution vector. */ - inline su2double *GetSolution_Vel(unsigned long iPoint) final { return Solution_Vel[iPoint]; } + inline su2double *GetSolution_Vel(unsigned long iPoint) final { return &Solution_Vel(iPoint,0); } /*! * \brief Get the velocity of the nodes (Structural Analysis) at time n. @@ -182,7 +198,7 @@ class CFEAVariable : public CVariable { * \brief Get the solution at time n. * \return Pointer to the solution (at time n) vector. */ - inline su2double *GetSolution_Vel_time_n(unsigned long iPoint) final { return Solution_Vel_time_n[iPoint]; } + inline su2double *GetSolution_Vel_time_n(unsigned long iPoint) final { return &Solution_Vel_time_n(iPoint,0); } /*! * \brief Set the value of the acceleration (Structural Analysis). @@ -210,11 +226,6 @@ class CFEAVariable : public CVariable { Solution_Accel_time_n(iPoint,iVar) = val_solution_accel_time_n[iVar]; } - /*! - * \brief Set the value of the acceleration (Structural Analysis) at time n. - */ - void SetSolution_Accel_time_n() final; - /*! * \overload * \param[in] iVar - Index of the variable. @@ -235,7 +246,7 @@ class CFEAVariable : public CVariable { * \brief Get the solution of the problem. * \return Pointer to the solution vector. */ - inline su2double *GetSolution_Accel(unsigned long iPoint) final { return Solution_Accel[iPoint]; } + inline su2double *GetSolution_Accel(unsigned long iPoint) final { return &Solution_Accel(iPoint,0); } /*! * \brief Get the acceleration of the nodes (Structural Analysis) at time n. @@ -250,13 +261,13 @@ class CFEAVariable : public CVariable { * \brief Get the solution at time n. * \return Pointer to the solution (at time n) vector. */ - inline su2double *GetSolution_Accel_time_n(unsigned long iPoint) final { return Solution_Accel_time_n[iPoint]; } + inline su2double *GetSolution_Accel_time_n(unsigned long iPoint) final { return &Solution_Accel_time_n(iPoint,0); } /*! * \brief Set the value of the solution velocity predictor. */ - inline void SetSolution_Vel_Pred(unsigned long iPoint) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Vel_Pred(iPoint,iVar) = Solution_Vel(iPoint,iVar); + inline void SetSolution_Vel_Pred(unsigned long iPoint, const su2double *val_solution_pred) final { + for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution_Vel_Pred(iPoint,iVar) = val_solution_pred[iVar]; } /*! @@ -335,104 +346,4 @@ class CFEAVariable : public CVariable { */ inline const su2double* GetReference_Geometry(unsigned long iPoint) const final { return Reference_Geometry[iPoint]; } - /*! - * \brief Register the variables in the solution time_n array as input/output variable. - * \param[in] input - input or output variables. - */ - void Register_femSolution_time_n() final; - - /*! - * \brief Register the variables in the velocity array as input/output variable. - * \param[in] input - input or output variables. - */ - void RegisterSolution_Vel(bool input) final; - - /*! - * \brief Register the variables in the velocity time_n array as input/output variable. - */ - void RegisterSolution_Vel_time_n() final; - - /*! - * \brief Register the variables in the acceleration array as input/output variable. - * \param[in] input - input or output variables. - */ - void RegisterSolution_Accel(bool input) final; - - /*! - * \brief Register the variables in the acceleration time_n array as input/output variable. - */ - void RegisterSolution_Accel_time_n() final; - - /*! - * \brief Set the velocity adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void SetAdjointSolution_Vel(unsigned long iPoint, const su2double *adj_sol) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution_Vel(iPoint,iVar), SU2_TYPE::GetValue(adj_sol[iVar])); - } - - /*! - * \brief Get the velocity adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void GetAdjointSolution_Vel(unsigned long iPoint, su2double *adj_sol) const final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_Vel(iPoint,iVar)); - } - - /*! - * \brief Set the velocity adjoint values of the solution at time n. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void SetAdjointSolution_Vel_time_n(unsigned long iPoint, const su2double *adj_sol) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution_Vel_time_n(iPoint,iVar), SU2_TYPE::GetValue(adj_sol[iVar])); - } - - /*! - * \brief Get the velocity adjoint values of the solution at time n. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void GetAdjointSolution_Vel_time_n(unsigned long iPoint, su2double *adj_sol) const final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_Vel_time_n(iPoint,iVar)); - } - - /*! - * \brief Set the acceleration adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void SetAdjointSolution_Accel(unsigned long iPoint, const su2double *adj_sol) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution_Accel(iPoint,iVar), SU2_TYPE::GetValue(adj_sol[iVar])); - } - - /*! - * \brief Get the acceleration adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void GetAdjointSolution_Accel(unsigned long iPoint, su2double *adj_sol) const final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_Accel(iPoint,iVar)); - } - - /*! - * \brief Set the acceleration adjoint values of the solution at time n. - * \param[in] adj_sol - The adjoint values of the solution. - */ - void SetAdjointSolution_Accel_time_n(unsigned long iPoint, const su2double *adj_sol) final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution_Accel_time_n(iPoint,iVar), SU2_TYPE::GetValue(adj_sol[iVar])); - } - - /*! - * \brief Get the acceleration adjoint values of the solution at time n. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void GetAdjointSolution_Accel_time_n(unsigned long iPoint, su2double *adj_sol) const final { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_Accel_time_n(iPoint,iVar)); - } - }; diff --git a/SU2_CFD/include/variables/CMeshBoundVariable.hpp b/SU2_CFD/include/variables/CMeshBoundVariable.hpp index ae054174566..0ed2738d8a5 100644 --- a/SU2_CFD/include/variables/CMeshBoundVariable.hpp +++ b/SU2_CFD/include/variables/CMeshBoundVariable.hpp @@ -117,9 +117,8 @@ class CMeshBoundVariable final : public CMeshVariable { /*! * \brief Register the boundary displacements of the mesh. - * \param[in] input - Defines whether we are registering the variable as input or as output. */ - void Register_BoundDisp(bool input) override; + void Register_BoundDisp() override; /*! * \brief Recover the value of the adjoint of the boundary displacements. diff --git a/SU2_CFD/include/variables/CMeshVariable.hpp b/SU2_CFD/include/variables/CMeshVariable.hpp index 1501d1bfc10..217c51ce5f3 100644 --- a/SU2_CFD/include/variables/CMeshVariable.hpp +++ b/SU2_CFD/include/variables/CMeshVariable.hpp @@ -87,16 +87,17 @@ class CMeshVariable : public CVariable { /*! * \brief Register the reference coordinates of the mesh. - * \param[in] input - Defines whether we are registering the variable as input or as output. */ - void Register_MeshCoord(bool input) final; + void Register_MeshCoord() final; /*! * \brief Recover the value of the adjoint of the mesh coordinates. */ - inline void GetAdjoint_MeshCoord(unsigned long iPoint, su2double *adj_mesh) const final { - for (unsigned long iDim = 0; iDim < nDim; iDim++) + inline void GetAdjoint_MeshCoord(unsigned long iPoint, su2double *adj_mesh) final { + for (unsigned long iDim = 0; iDim < nDim; iDim++) { adj_mesh[iDim] = SU2_TYPE::GetDerivative(Mesh_Coord(iPoint,iDim)); + AD::ResetInput(Mesh_Coord(iPoint,iDim)); + } } }; diff --git a/SU2_CFD/include/variables/CNSVariable.hpp b/SU2_CFD/include/variables/CNSVariable.hpp index 3de4dfa849a..876605c3de3 100644 --- a/SU2_CFD/include/variables/CNSVariable.hpp +++ b/SU2_CFD/include/variables/CNSVariable.hpp @@ -170,6 +170,7 @@ class CNSVariable final : public CEulerVariable { * \return Value of the wall shear stress computed by a wall function. */ inline su2double GetTauWall(unsigned long iPoint) const override { return Tau_Wall(iPoint); } + inline const VectorType& GetTauWall() const { return Tau_Wall; } /*! * \brief Get the DES length scale diff --git a/SU2_CFD/include/variables/CVariable.hpp b/SU2_CFD/include/variables/CVariable.hpp index 54c62b153db..e83e6c1376a 100644 --- a/SU2_CFD/include/variables/CVariable.hpp +++ b/SU2_CFD/include/variables/CVariable.hpp @@ -41,8 +41,6 @@ class CFluidModel; class CNEMOGas; -using namespace std; - /*! * \class CVariable * \brief Main class for defining the variables. @@ -78,7 +76,7 @@ class CVariable { MatrixType Solution_Min; /*!< \brief Min solution for limiter computation. */ MatrixType AuxVar; /*!< \brief Auxiliary variable for gradient computation. */ - CVectorOfMatrix Grad_AuxVar; /*!< \brief Gradient of the auxiliary variables of the problem. */ + CVectorOfMatrix Grad_AuxVar; /*!< \brief Gradient of the auxiliary variables of the problem. */ VectorType Max_Lambda_Inv; /*!< \brief Maximun inviscid eingenvalue. */ VectorType Max_Lambda_Visc; /*!< \brief Maximun viscous eingenvalue. */ @@ -112,6 +110,25 @@ class CVariable { assert(false && "A base method of CVariable was used, but it should have been overridden by the derived class."); } + void RegisterContainer(bool input, su2activematrix& variable, su2matrix* ad_index = nullptr) { + const auto nPoint = variable.rows(); + SU2_OMP_FOR_STAT(roundUpDiv(nPoint,omp_get_num_threads())) + for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) { + for(unsigned long iVar=0; iVar& ad_index) { + RegisterContainer(input, variable, &ad_index); + } + public: /*--- Disable copy and assignment. ---*/ CVariable(const CVariable&) = delete; @@ -133,8 +150,9 @@ class CVariable { * \param[in] ndim - Number of dimensions of the problem. * \param[in] nvar - Number of variables of the problem. * \param[in] config - Definition of the particular problem. + * \param[in] adjoint - True if derived class is an adjoint variable. */ - CVariable(unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config); + CVariable(unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config, bool adjoint = false); /*! * \brief Destructor of the class. @@ -367,9 +385,9 @@ class CVariable { void SetExternalZero(); /*! - * \brief Set old External to the value of the current variables. + * \brief Set Dual-time derivative contributions to the external. */ - void Set_OldExternal(); + inline virtual void Set_External_To_DualTimeDer() { SetExternalZero(); } /*! * \brief A virtual member. @@ -1801,30 +1819,6 @@ class CVariable { return Solution_BGS_k(iPoint,iVar); } - /*! - * \brief A virtual member. Set the direct velocity solution for the adjoint solver. - * \param[in] solution_direct - Value of the direct velocity solution. - */ - inline virtual void SetSolution_Vel_Direct(unsigned long iPoint, const su2double *sol) {} - - /*! - * \brief A virtual member. Set the direct acceleration solution for the adjoint solver. - * \param[in] solution_direct - Value of the direct acceleration solution. - */ - inline virtual void SetSolution_Accel_Direct(unsigned long iPoint, const su2double *sol) {} - - /*! - * \brief A virtual member. Get the direct velocity solution for the adjoint solver. - * \return Pointer to the direct velocity solution vector. - */ - inline virtual su2double* GetSolution_Vel_Direct(unsigned long iPoint) { return nullptr; } - - /*! - * \brief A virtual member. Get the direct acceleraction solution for the adjoint solver. - * \return Pointer to the direct acceleraction solution vector. - */ - inline virtual su2double* GetSolution_Accel_Direct(unsigned long iPoint) { return nullptr; } - /*! * \brief Set the value of the velocity (Structural Analysis). * \param[in] solution - Solution of the problem (velocity). @@ -1844,11 +1838,6 @@ class CVariable { */ inline virtual void SetSolution_Vel_time_n(unsigned long iPoint, const su2double *solution_vel_time_n) {} - /*! - * \brief Set the value of the velocity (Structural Analysis) at time n. - */ - inline virtual void SetSolution_Vel_time_n() {} - /*! * \overload * \param[in] iVar - Index of the variable. @@ -1916,11 +1905,6 @@ class CVariable { */ inline virtual void SetSolution_Accel_time_n(unsigned long iPoint, const su2double *solution_accel_time_n) {} - /*! - * \brief Set the value of the acceleration (Structural Analysis) at time n. - */ - inline virtual void SetSolution_Accel_time_n() {} - /*! * \overload * \param[in] iVar - Index of the variable. @@ -1954,20 +1938,10 @@ class CVariable { */ inline virtual su2double *GetSolution_Accel_time_n(unsigned long iPoint) { return nullptr; } - /*! - * \brief A virtual member. - */ - inline virtual void Set_OldSolution_Vel() {} - - /*! - * \brief A virtual member. - */ - inline virtual void Set_OldSolution_Accel() {} - /*! * \brief A virtual member. Set the value of the velocity solution predictor. */ - inline virtual void SetSolution_Vel_Pred(unsigned long iPoint) {} + inline virtual void SetSolution_Vel_Pred(unsigned long iPoint, const su2double *val_solution_pred) { } /*! * \brief A virtual member. Set the value of the old solution. @@ -2059,14 +2033,13 @@ class CVariable { /*! * \brief A virtual member. Register the reference coordinates of the mesh. - * \param[in] input - Defines whether we are registering the variable as input or as output. */ - inline virtual void Register_MeshCoord(bool input) { } + inline virtual void Register_MeshCoord() { } /*! * \brief A virtual member. Recover the value of the adjoint of the mesh coordinates. */ - inline virtual void GetAdjoint_MeshCoord(unsigned long iPoint, su2double *adj_mesh) const { } + inline virtual void GetAdjoint_MeshCoord(unsigned long iPoint, su2double *adj_mesh) { } /*! * \brief A virtual member. Get the value of the displacement imposed at the boundary. @@ -2133,45 +2106,14 @@ class CVariable { /*! * \brief A virtual member. Register the boundary displacements of the mesh. - * \param[in] input - Defines whether we are registering the variable as input or as output. */ - inline virtual void Register_BoundDisp(bool input) { } + inline virtual void Register_BoundDisp() { } /*! * \brief A virtual member. Recover the value of the adjoint of the boundary displacements. */ inline virtual void GetAdjoint_BoundDisp(unsigned long iPoint, su2double *adj_disp) const { } - /*! - * \brief A virtual member. - */ - inline virtual void Register_femSolution_time_n() {} - - /*! - * \brief A virtual member. - */ - inline virtual void RegisterSolution_Vel(bool input) {} - - /*! - * \brief A virtual member. - */ - inline virtual void RegisterSolution_Vel_time_n() {} - - /*! - * \brief A virtual member. - */ - inline virtual void RegisterSolution_Accel(bool input) {} - - /*! - * \brief A virtual member. - */ - inline virtual void RegisterSolution_Accel_time_n() {} - - /*! - * \brief A virtual member. - */ - inline virtual void SetAdjointSolution_Vel(unsigned long iPoint, const su2double *adj_sol) {} - /*! * \brief A virtual member. */ @@ -2182,47 +2124,11 @@ class CVariable { */ inline virtual su2double ExtractFlowTraction_Sensitivity(unsigned long iPoint, unsigned long iDim) const { return 0.0; } - /*! - * \brief A virtual member. - */ - inline virtual void GetAdjointSolution_Vel(unsigned long iPoint, su2double *adj_sol) const {} - - /*! - * \brief A virtual member. - */ - inline virtual void SetAdjointSolution_Vel_time_n(unsigned long iPoint, const su2double *adj_sol) {} - - /*! - * \brief A virtual member. - */ - inline virtual void GetAdjointSolution_Vel_time_n(unsigned long iPoint, su2double *adj_sol) const {} - - /*! - * \brief A virtual member. - */ - inline virtual void SetAdjointSolution_Accel(unsigned long iPoint, const su2double *adj_sol) {} - - /*! - * \brief A virtual member. - */ - inline virtual void GetAdjointSolution_Accel(unsigned long iPoint, su2double *adj_sol) const {} - - /*! - * \brief A virtual member. - */ - inline virtual void SetAdjointSolution_Accel_time_n(unsigned long iPoint, const su2double *adj_sol) {} - - /*! - * \brief A virtual member. - */ - inline virtual void GetAdjointSolution_Accel_time_n(unsigned long iPoint, su2double *adj_sol) const {} - /*! * \brief Register the variables in the solution array as input/output variable. * \param[in] input - input or output variables. - * \param[in] push_index - boolean whether we want to push the index or save it in a member variable. */ - void RegisterSolution(bool input, bool push_index = true); + void RegisterSolution(bool input); /*! * \brief Register the variables in the solution_time_n array as input/output variable. @@ -2239,52 +2145,26 @@ class CVariable { * \param[in] adj_sol - The adjoint values of the solution. */ inline void SetAdjointSolution(unsigned long iPoint, const su2double *adj_sol) { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - SU2_TYPE::SetDerivative(Solution(iPoint,iVar), SU2_TYPE::GetValue(adj_sol[iVar])); - } - - /*! - * \brief Set the adjoint values of the solution. - * \param[in] adj_sol - The adjoint values of the solution. - */ - inline void SetAdjointSolution_LocalIndex(unsigned long iPoint, const su2double *adj_sol) { - for (unsigned long iVar = 0; iVar < nVar; iVar++) + for (unsigned long iVar = 0; iVar < AD_OutputIndex.cols(); iVar++) AD::SetDerivative(AD_OutputIndex(iPoint,iVar), SU2_TYPE::GetValue(adj_sol[iVar])); } - /*! - * \brief Get the adjoint values of the solution. - * \param[out] adj_sol - The adjoint values of the solution. - */ - inline void GetAdjointSolution(unsigned long iPoint, su2double *adj_sol) const { - for (unsigned long iVar = 0; iVar < nVar; iVar++) - adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution(iPoint,iVar)); - } - /*! * \brief Get the adjoint values of the solution. * \param[in] adj_sol - The adjoint values of the solution. */ - inline void GetAdjointSolution_LocalIndex(unsigned long iPoint, su2double *adj_sol) const { - for (unsigned long iVar = 0; iVar < nVar; iVar++) + inline void GetAdjointSolution(unsigned long iPoint, su2double *adj_sol) const { + for (unsigned long iVar = 0; iVar < AD_InputIndex.cols(); iVar++) adj_sol[iVar] = AD::GetDerivative(AD_InputIndex(iPoint,iVar)); } - /*! - * \brief Get the adjoint values of the solution at time n. - * \param[out] adj_sol - The adjoint values of the solution. - */ inline void GetAdjointSolution_time_n(unsigned long iPoint, su2double *adj_sol) const { - for (unsigned long iVar = 0; iVar < nVar; iVar++) + for (unsigned long iVar = 0; iVar < Solution_time_n.cols(); iVar++) adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_time_n(iPoint,iVar)); } - /*! - * \brief Get the adjoint values of the solution at time n-1. - * \param[out] adj_sol - The adjoint values of the solution. - */ inline void GetAdjointSolution_time_n1(unsigned long iPoint, su2double *adj_sol) const { - for (unsigned long iVar = 0; iVar < nVar; iVar++) + for (unsigned long iVar = 0; iVar < Solution_time_n1.cols(); iVar++) adj_sol[iVar] = SU2_TYPE::GetDerivative(Solution_time_n1(iPoint,iVar)); } @@ -2302,14 +2182,6 @@ class CVariable { */ inline virtual su2double GetSensitivity(unsigned long iPoint, unsigned long iDim) const { return 0.0; } - inline virtual void SetDual_Time_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual void SetDual_Time_Derivative_n(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual su2double GetDual_Time_Derivative(unsigned long iPoint, unsigned long iVar) const {return 0.0;} - - inline virtual su2double GetDual_Time_Derivative_n(unsigned long iPoint, unsigned long iVar) const {return 0.0;} - inline virtual void SetTauWall(unsigned long iPoint, su2double val_tau_wall) {} inline virtual su2double GetTauWall(unsigned long iPoint) const { return 0.0; } @@ -2319,34 +2191,6 @@ class CVariable { inline virtual su2double GetVortex_Tilting(unsigned long iPoint) const { return 0.0; } - inline virtual void SetDynamic_Derivative(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual void SetDynamic_Derivative_n(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual su2double GetDynamic_Derivative(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual su2double GetDynamic_Derivative_n(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual void SetDynamic_Derivative_Vel(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual void SetDynamic_Derivative_Vel_n(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual su2double GetDynamic_Derivative_Vel(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual su2double GetDynamic_Derivative_Vel_n(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual void SetDynamic_Derivative_Accel(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual void SetDynamic_Derivative_Accel_n(unsigned long iPoint, unsigned long iVar, su2double der) {} - - inline virtual su2double GetDynamic_Derivative_Accel(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual su2double GetDynamic_Derivative_Accel_n(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual su2double GetSolution_Old_Vel(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - - inline virtual su2double GetSolution_Old_Accel(unsigned long iPoint, unsigned long iVar) const { return 0.0; } - /*! * \brief A virtual member: Set the recovered pressure for streamwise periodic flow. * \param[in] iPoint - Point index. @@ -2413,6 +2257,7 @@ class CVariable { * \param[in] val - value of the source term */ virtual void SetSourceTerm_DispAdjoint(unsigned long iPoint, unsigned long iDim, su2double val) { } + virtual void SetSourceTerm_VelAdjoint(unsigned long iPoint, unsigned long iDim, su2double val) { } /*! * \brief Get the source term applied into the displacement adjoint coming from external solvers @@ -2420,5 +2265,6 @@ class CVariable { * \return value of the source term */ virtual su2double GetSourceTerm_DispAdjoint(unsigned long iPoint, unsigned long iDim) const { return 0.0; } + virtual su2double GetSourceTerm_VelAdjoint(unsigned long iPoint, unsigned long iDim) const { return 0.0; } }; diff --git a/SU2_CFD/obj/Makefile.am b/SU2_CFD/obj/Makefile.am index 054df6fa267..6b7f7854ac9 100644 --- a/SU2_CFD/obj/Makefile.am +++ b/SU2_CFD/obj/Makefile.am @@ -136,6 +136,7 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/output/output_physics.cpp \ ../src/output/CMeshOutput.cpp \ ../src/output/CElasticityOutput.cpp \ + ../src/output/CFVMOutput.cpp \ ../src/output/CFlowOutput.cpp \ ../src/output/CFlowCompOutput.cpp \ ../src/output/CFlowCompFEMOutput.cpp \ @@ -203,7 +204,6 @@ libSU2Core_sources = ../src/definition_structure.cpp \ ../src/variables/CAdjTurbVariable.cpp \ ../src/variables/CTransLMVariable.cpp \ ../src/variables/CDiscAdjFEABoundVariable.cpp \ - ../src/variables/CDiscAdjFEAVariable.cpp \ ../src/variables/CIncEulerVariable.cpp \ ../src/variables/CTurbVariable.cpp \ ../src/variables/CNSVariable.cpp \ diff --git a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp index 2441cf94e94..c52d5afe0e0 100644 --- a/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjMultizoneDriver.cpp @@ -125,8 +125,43 @@ CDiscAdjMultizoneDriver::~CDiscAdjMultizoneDriver(){ } +void CDiscAdjMultizoneDriver::Preprocess(unsigned long TimeIter) { + + const bool time_domain = driver_config->GetTime_Domain(); + + for (iZone = 0; iZone < nZone; iZone++) { + /*--- Set current time iteration ---*/ + config_container[iZone]->SetTimeIter(TimeIter); + + if (time_domain) + config_container[iZone]->SetPhysicalTime(static_cast(TimeIter)*config_container[iZone]->GetDelta_UnstTimeND()); + else + config_container[iZone]->SetPhysicalTime(0.0); + + /*--- Preprocess the iteration of each zone. ---*/ + + iteration_container[iZone][INST_0]->Preprocess(output_container[iZone], integration_container, geometry_container, + solver_container, numerics_container, config_container, surface_movement, + grid_movement, FFDBox, iZone, INST_0); + } + + if (TimeIter) { + /*--- Reset cross-terms before new time iterations. ---*/ + for (auto& matOfMat : Cross_Terms) + for (auto& vecOfMat : matOfMat) + for (auto& mat : vecOfMat) + mat = 0.0; + + /*--- Initialize external with dynamic contributions. ---*/ + Set_External_To_DualTimeDer(); + } + +} + void CDiscAdjMultizoneDriver::StartSolver() { + const bool time_domain = driver_config->GetTime_Domain(); + /*--- Main external loop of the solver. Runs for the number of time steps required. ---*/ if (rank == MASTER_NODE) { @@ -134,30 +169,51 @@ void CDiscAdjMultizoneDriver::StartSolver() { cout << "\nSimulation Run using the Discrete Adjoint Multizone Driver" << endl; - if (driver_config->GetTime_Domain()) - SU2_MPI::Error("The discrete adjoint multizone driver is not ready for unsteady computations yet.", - CURRENT_FUNCTION); + if (time_domain) + cout << "The simulation will run for " << driver_config->GetnTime_Iter() << " time steps." << endl; } - for (iZone = 0; iZone < nZone; iZone++){ + /*--- General setup. ---*/ + + for (iZone = 0; iZone < nZone; iZone++) { + wrt_sol_freq = min(wrt_sol_freq, config_container[iZone]->GetVolume_Wrt_Freq()); + + /*--- Set BGS_Solution_k to Solution, this is needed to restart + * correctly as the first OF gradient will overwrite the solution. ---*/ + + Set_BGSSolution_k_To_Solution(iZone); - /*--- Set the value of the external iteration to TimeIter. -------------------------------------*/ - /*--- TODO: This should be generalised for an homogeneous criteria throughout the code. --------*/ - config_container[iZone]->SetTimeIter(0); + /*--- Prepare Krylov or quasi-Newton methods. ---*/ + + const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint(); + const auto nPointDomain = geometry_container[iZone][INST_0][MESH_0]->GetnPointDomain(); + const auto nVar = GetTotalNumberOfVariables(iZone, true); + if (config_container[iZone]->GetNewtonKrylov() && + config_container[iZone]->GetnQuasiNewtonSamples() >= KrylovMinIters) { + AdjRHS[iZone].Initialize(nPoint, nPointDomain, nVar, nullptr); + AdjSol[iZone].Initialize(nPoint, nPointDomain, nVar, nullptr); + LinSolver[iZone].SetToleranceType(LinearToleranceType::RELATIVE); + } + else if (config_container[iZone]->GetnQuasiNewtonSamples() > 1) { + FixPtCorrector[iZone].resize(config_container[iZone]->GetnQuasiNewtonSamples(), nPoint, nVar, nPointDomain); + } } /*--- Size and initialize the matrix of cross-terms. ---*/ InitializeCrossTerms(); - /*--- We directly start the (steady-state) discrete adjoint computation. ---*/ + /*--- Run time iterations. ---*/ + + while (TimeIter < driver_config->GetnTime_Iter()) { - Run(); + Preprocess(TimeIter); - /*--- Output the solution in files. ---*/ + Run(); - Output(TimeIter); + TimeIter++; + } } @@ -174,9 +230,8 @@ bool CDiscAdjMultizoneDriver::Iterate(unsigned short iZone, unsigned long iInner /*--- Extracting adjoints for solvers in iZone w.r.t. to outputs in iZone (diagonal part). ---*/ - iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, iZone, INST_0); + iteration_container[iZone][INST_0]->IterateDiscAdj(geometry_container, solver_container, + config_container, iZone, INST_0, false); /*--- Use QN driver to improve the solution. ---*/ @@ -198,73 +253,68 @@ bool CDiscAdjMultizoneDriver::Iterate(unsigned short iZone, unsigned long iInner surface_movement, grid_movement, FFDBox, iZone, INST_0); } -void CDiscAdjMultizoneDriver::Run() { - - unsigned long wrt_sol_freq = 9999; - const auto nOuterIter = driver_config->GetnOuter_Iter(); +void CDiscAdjMultizoneDriver::KrylovInnerIters(unsigned short iZone) { - for (iZone = 0; iZone < nZone; iZone++) { - - wrt_sol_freq = min(wrt_sol_freq, config_container[iZone]->GetVolume_Wrt_Freq()); + /*--- Use FGMRES to solve the adjoint system, the RHS is -External, + * the solution are the iZone adjoint variables + External, + * Recall that External also contains the OF gradient. ---*/ - iteration_container[iZone][INST_0]->Preprocess(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, surface_movement, - grid_movement, FFDBox, iZone, INST_0); + GetAdjointRHS(iZone, AdjRHS[iZone]); - /*--- Set BGS_Solution_k to Solution, this is needed to restart - * correctly as the OF gradient will overwrite the solution. ---*/ + Add_External_To_Solution(iZone); - Set_BGSSolution_k_To_Solution(iZone); + GetAllSolutions(iZone, true, AdjSol[iZone]); - /*--- Prepare Krylov or quasi-Newton methods. ---*/ + const bool monitor = config_container[iZone]->GetWrt_ZoneConv(); + const auto product = AdjointProduct(this, iZone); - const auto nPoint = geometry_container[iZone][INST_0][MESH_0]->GetnPoint(); - const auto nPointDomain = geometry_container[iZone][INST_0][MESH_0]->GetnPointDomain(); - const auto nVar = GetTotalNumberOfVariables(iZone, true); + /*--- Manipulate the screen output frequency to avoid printing garbage. ---*/ + const auto wrtFreq = config_container[iZone]->GetScreen_Wrt_Freq(2); + config_container[iZone]->SetScreen_Wrt_Freq(2, nInnerIter[iZone]); + LinSolver[iZone].SetMonitoringFrequency(wrtFreq); - if (config_container[iZone]->GetNewtonKrylov() && - config_container[iZone]->GetnQuasiNewtonSamples() >= KrylovMinIters) { - AdjRHS[iZone].Initialize(nPoint, nPointDomain, nVar, nullptr); - AdjSol[iZone].Initialize(nPoint, nPointDomain, nVar, nullptr); - LinSolver[iZone].SetToleranceType(LinearToleranceType::RELATIVE); - } - else if (config_container[iZone]->GetnQuasiNewtonSamples() > 1) { - FixPtCorrector[iZone].resize(config_container[iZone]->GetnQuasiNewtonSamples(), nPoint, nVar, nPointDomain); - } + Scalar eps = 1.0; + for (auto totalIter = nInnerIter[iZone]; totalIter >= KrylovMinIters && eps > KrylovTol;) { + Scalar eps_l = 0.0; + Scalar tol_l = KrylovTol / eps; + auto iter = min(totalIter-2ul, config_container[iZone]->GetnQuasiNewtonSamples()-2ul); + iter = LinSolver[iZone].FGMRES_LinSolver(AdjRHS[iZone], AdjSol[iZone], product, Identity(), + tol_l, iter, eps_l, monitor, config_container[iZone]); + totalIter -= iter+1; + eps *= eps_l; } - /*--- Evaluate the objective function gradient w.r.t. the solutions of all zones. ---*/ + /*--- Store the solution and restore user settings. ---*/ + SetAllSolutions(iZone, true, AdjSol[iZone]); + config_container[iZone]->SetScreen_Wrt_Freq(2, wrtFreq); - SetRecording(RECORDING::CLEAR_INDICES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); - SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); - RecordingState = RECORDING::CLEAR_INDICES; + /*--- Set the old solution such that iterating gives meaningful residuals. ---*/ + AdjSol[iZone] += AdjRHS[iZone]; + SetAllSolutionsOld(iZone, true, AdjSol[iZone]); - AD::ClearAdjoints(); - SetAdj_ObjFunction(); - AD::ComputeAdjoint(OBJECTIVE_FUNCTION, START); + /*--- Iterate to evaluate cross terms and residuals, this cannot happen within GMRES + * because the vectors it multiplies by the Jacobian are not the actual solution. ---*/ + eval_transfer = true; + Iterate(iZone, product.iInnerIter); - /*--- Initialize External with the objective function gradient. ---*/ + /*--- Set the solution as obtained from GMRES, otherwise it would be GMRES+Iterate once. + * This is set without the "External" (by adding RHS above) so that it can be added + * again in the next outer iteration with new contributions from other zones. ---*/ + SetAllSolutions(iZone, true, AdjSol[iZone]); - su2double rhs_norm = 0.0; +} - for (iZone = 0; iZone < nZone; iZone++) { +void CDiscAdjMultizoneDriver::Run() { - iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, iZone, INST_0); - Add_Solution_To_External(iZone); + const unsigned long nOuterIter = driver_config->GetnOuter_Iter(); + const bool time_domain = driver_config->GetTime_Domain(); - for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { - auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; - if (solver && solver->GetAdjoint()) - for (unsigned short iVar=0; iVar < solver->GetnVar(); ++iVar) - rhs_norm += solver->GetRes_RMS(iVar); - } - } + /*--- If the gradient of the objective function is 0 so are the adjoint variables. + * Unless in unsteady problems where there are other contributions to the RHS. ---*/ - /*--- If the gradient of the objective function is 0 so are the adjoint variables. ---*/ + const auto zeroGrad = EvaluateObjectiveFunctionGradient(); - if (rhs_norm < EPS) { + if (zeroGrad && !time_domain) { if (rank == MASTER_NODE) { cout << "\nThe gradient of the objective function is numerically 0."; cout << "\nThis implies that the adjoint variables are also 0.\n\n"; @@ -353,52 +403,9 @@ void CDiscAdjMultizoneDriver::Run() { } } else { - /*--- Use FGMRES to solve the adjoint system, the RHS is -External, - * the solution are the iZone adjoint variables + External, - * Recall that External also contains the OF gradient. ---*/ - - GetAdjointRHS(iZone, AdjRHS[iZone]); - - Add_External_To_Solution(iZone); - - GetAllSolutions(iZone, true, AdjSol[iZone]); - - const bool monitor = config_container[iZone]->GetWrt_ZoneConv(); - const auto product = AdjointProduct(this, iZone); + /*--- Use Krylov method to drive inner iterations of this zone. ---*/ - /*--- Manipulate the screen output frequency to avoid printing garbage. ---*/ - const auto wrtFreq = config_container[iZone]->GetScreen_Wrt_Freq(2); - config_container[iZone]->SetScreen_Wrt_Freq(2, nInnerIter[iZone]); - LinSolver[iZone].SetMonitoringFrequency(wrtFreq); - - Scalar eps = 1.0; - for (auto totalIter = nInnerIter[iZone]; totalIter >= KrylovMinIters && eps > KrylovTol;) { - Scalar eps_l = 0.0; - Scalar tol_l = KrylovTol / eps; - auto iter = min(totalIter-2ul, config_container[iZone]->GetnQuasiNewtonSamples()-2ul); - iter = LinSolver[iZone].FGMRES_LinSolver(AdjRHS[iZone], AdjSol[iZone], product, Identity(), - tol_l, iter, eps_l, monitor, config_container[iZone]); - totalIter -= iter+1; - eps *= eps_l; - } - - /*--- Store the solution and restore user settings. ---*/ - SetAllSolutions(iZone, true, AdjSol[iZone]); - config_container[iZone]->SetScreen_Wrt_Freq(2, wrtFreq); - - /*--- Set the old solution such that iterating gives meaningful residuals. ---*/ - AdjSol[iZone] += AdjRHS[iZone]; - SetAllSolutionsOld(iZone, true, AdjSol[iZone]); - - /*--- Iterate to evaluate cross terms and residuals, this cannot happen within GMRES - * because the vectors it multiplies by the Jacobian are not the actual solution. ---*/ - eval_transfer = true; - Iterate(iZone, product.iInnerIter); - - /*--- Set the solution as obtained from GMRES, otherwise it would be GMRES+Iterate once. - * This is set without the "External" (by adding RHS above) so that it can be added - * again in the next outer iteration with new contributions from other zones. ---*/ - SetAllSolutions(iZone, true, AdjSol[iZone]); + KrylovInnerIters(iZone); } /*--- Off-diagonal (coupling term) BGS update. ---*/ @@ -411,9 +418,8 @@ void CDiscAdjMultizoneDriver::Run() { * that is, for the cases iZone != jZone we are evaluating cross derivatives between zones. ---*/ config_container[jZone]->SetInnerIter(0); - iteration_container[jZone][INST_0]->Iterate(output_container[jZone], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, jZone, INST_0); + iteration_container[jZone][INST_0]->IterateDiscAdj(geometry_container, solver_container, + config_container, jZone, INST_0, true); /*--- Extract the cross-term performing a relaxed update of it and of the sum (External) for jZone. ---*/ @@ -429,7 +435,7 @@ void CDiscAdjMultizoneDriver::Run() { /*--- Set the multizone output. ---*/ - driver_output->SetMultizoneHistory_Output(output_container, config_container, driver_config, 0, iOuterIter); + driver_output->SetMultizoneHistory_Output(output_container, config_container, driver_config, TimeIter, iOuterIter); /*--- Check for convergence. ---*/ @@ -440,16 +446,54 @@ void CDiscAdjMultizoneDriver::Run() { AD::ClearAdjoints(); - /*--- Compute the geometrical sensitivities and write them to file. ---*/ + /*--- Compute the geometrical sensitivities and write them to file, except for time_domain. ---*/ - bool checkSensitivity = StopCalc || ((iOuterIter % wrt_sol_freq == 0) && (iOuterIter != 0)); + if (time_domain) continue; - if (checkSensitivity) + if (StopCalc || ((iOuterIter % wrt_sol_freq == 0) && (iOuterIter != 0))) EvaluateSensitivities(iOuterIter, StopCalc); } + + if (time_domain) { + EvaluateSensitivities(TimeIter, (TimeIter+1) == driver_config->GetnTime_Iter()); + } + +} + +bool CDiscAdjMultizoneDriver::EvaluateObjectiveFunctionGradient() { + + /*--- Evaluate the objective function gradient w.r.t. the solutions of all zones. ---*/ + + SetRecording(RECORDING::CLEAR_INDICES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); + SetRecording(RECORDING::SOLUTION_VARIABLES, Kind_Tape::OBJECTIVE_FUNCTION_TAPE, ZONE_0); + RecordingState = RECORDING::CLEAR_INDICES; + + AD::ClearAdjoints(); + SetAdj_ObjFunction(); + AD::ComputeAdjoint(OBJECTIVE_FUNCTION, START); + + /*--- Initialize External with the objective function gradient. ---*/ + + su2double rhs_norm = 0.0; + + for (iZone = 0; iZone < nZone; iZone++) { + + iteration_container[iZone][INST_0]->IterateDiscAdj(geometry_container, solver_container, + config_container, iZone, INST_0, false); + Add_Solution_To_External(iZone); + + for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { + auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; + if (solver && solver->GetAdjoint()) + for (unsigned short iVar=0; iVar < solver->GetnVar(); ++iVar) + rhs_norm += solver->GetRes_RMS(iVar); + } + } + + return rhs_norm < EPS; } -void CDiscAdjMultizoneDriver::EvaluateSensitivities(unsigned long iOuterIter, bool StopCalc) { +void CDiscAdjMultizoneDriver::EvaluateSensitivities(unsigned long Iter, bool force_writing) { /*--- SetRecording stores the computational graph on one iteration of the direct problem. Calling it with NONE * as argument ensures that all information from a previous recording is removed. ---*/ @@ -489,49 +533,36 @@ void CDiscAdjMultizoneDriver::EvaluateSensitivities(unsigned long iOuterIter, bo auto solvers = solver_container[iZone][INST_0][MESH_0]; auto geometry = geometry_container[iZone][INST_0][MESH_0]; - switch (config_container[iZone]->GetKind_Solver()) { - - case DISC_ADJ_EULER: case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_RANS: - case DISC_ADJ_INC_EULER: case DISC_ADJ_INC_NAVIER_STOKES: case DISC_ADJ_INC_RANS: - - if(Has_Deformation(iZone)) { - solvers[ADJMESH_SOL]->SetSensitivity(geometry, config, solvers[ADJFLOW_SOL]); - } else { - solvers[ADJFLOW_SOL]->SetSensitivity(geometry, config); - } - break; - - case DISC_ADJ_HEAT: - - if(Has_Deformation(iZone)) { - solvers[ADJMESH_SOL]->SetSensitivity(geometry, config, solvers[ADJHEAT_SOL]); - } else { - solvers[ADJHEAT_SOL]->SetSensitivity(geometry, config); - } - break; - - case DISC_ADJ_FEM: + int IDX_SOL = -1; + if (config->GetFluidProblem()) IDX_SOL = ADJFLOW_SOL; + else if (config->GetHeatProblem()) IDX_SOL = ADJHEAT_SOL; + else if (config->GetStructuralProblem()) IDX_SOL = ADJFEA_SOL; + else { + if (rank == MASTER_NODE) + cout << "WARNING: Sensitivities not set for one of the specified discrete adjoint solvers!" << endl; + continue; + } - solvers[ADJFEA_SOL]->SetSensitivity(geometry, config); - break; + if (Has_Deformation(iZone)) + solvers[ADJMESH_SOL]->SetSensitivity(geometry, config, solvers[IDX_SOL]); + else + solvers[IDX_SOL]->SetSensitivity(geometry, config); - default: - if (rank == MASTER_NODE) - cout << "WARNING: Sensitivities not set for one of the specified discrete adjoint solvers!" << endl; - break; - } + iteration_container[iZone][INST_0]->Postprocess(output_container[iZone], integration_container, geometry_container, + solver_container, numerics_container, config_container, + surface_movement, grid_movement, FFDBox, iZone, INST_0); } /*--- Clear the stored adjoint information to be ready for a new evaluation. ---*/ AD::ClearAdjoints(); - for (iZone = 0; iZone < nZone; iZone++) { + /*--- Output files (CMultizoneDriver::Output uses StopCalc to force file output). ---*/ + + swap(StopCalc, force_writing); + Output(Iter); + swap(StopCalc, force_writing); - output_container[iZone]->SetResult_Files(geometry_container[iZone][INST_0][MESH_0], - config_container[iZone], - solver_container[iZone][INST_0][MESH_0], iOuterIter, StopCalc); - } } void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape tape_type, unsigned short record_zone) { @@ -554,7 +585,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t if (rank == MASTER_NODE) { cout << "\n-------------------------------------------------------------------------\n"; switch(kind_recording) { - case RECORDING::CLEAR_INDICES: cout << "Clearing the computational graph." << endl; break; + case RECORDING::CLEAR_INDICES: cout << "Clearing the computational graph." << endl; break; case RECORDING::MESH_COORDS: cout << "Storing computational graph wrt MESH COORDINATES." << endl; break; case RECORDING::SOLUTION_VARIABLES: cout << "Storing computational graph wrt CONSERVATIVE VARIABLES." << endl; break; default: break; @@ -631,7 +662,7 @@ void CDiscAdjMultizoneDriver::SetRecording(RECORDING kind_recording, Kind_Tape t DirectIteration(iZone, kind_recording); iteration_container[iZone][INST_0]->RegisterOutput(solver_container, geometry_container, - config_container, output_container[iZone], iZone, INST_0); + config_container, iZone, INST_0); AD::Push_TapePosition(); /// leave_zone } } @@ -879,7 +910,9 @@ void CDiscAdjMultizoneDriver::ComputeAdjoints(unsigned short iZone, bool eval_tr void CDiscAdjMultizoneDriver::InitializeCrossTerms() { - Cross_Terms.resize(nZone, vector >(nZone)); + if (Cross_Terms.empty()) { + Cross_Terms.resize(nZone, vector >(nZone)); + } for(auto iZone = 0u; iZone < nZone; iZone++) { for (auto jZone = 0u; jZone < nZone; jZone++) { @@ -916,7 +949,7 @@ void CDiscAdjMultizoneDriver::HandleDataTransfer() { for (unsigned short jZone = 0; jZone < nZone; jZone++){ /*--- The target zone is iZone ---*/ if (jZone != iZone && interface_container[jZone][iZone] != nullptr) { - DeformMesh = DeformMesh || Transfer_Data(jZone, iZone); + DeformMesh |= Transfer_Data(jZone, iZone); } } @@ -937,6 +970,17 @@ void CDiscAdjMultizoneDriver::Add_Solution_To_External(unsigned short iZone) { } } +void CDiscAdjMultizoneDriver::Set_External_To_DualTimeDer() { + + for (unsigned short iZone = 0; iZone < nZone; iZone++) { + for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { + auto solver = solver_container[iZone][INST_0][MESH_0][iSol]; + if (solver && solver->GetAdjoint()) + solver->GetNodes()->Set_External_To_DualTimeDer(); + } + } +} + void CDiscAdjMultizoneDriver::Add_External_To_Solution(unsigned short iZone) { for (unsigned short iSol=0; iSol < MAX_SOLS; iSol++) { diff --git a/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp b/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp index 7a70edca182..657785783e8 100644 --- a/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp +++ b/SU2_CFD/src/drivers/CDiscAdjSinglezoneDriver.cpp @@ -178,9 +178,8 @@ void CDiscAdjSinglezoneDriver::Run() { /*--- Extract the computed adjoint values of the input variables and store them for the next iteration. ---*/ - iteration->Iterate(output_container[ZONE_0], integration_container, geometry_container, - solver_container, numerics_container, config_container, - surface_movement, grid_movement, FFDBox, ZONE_0, INST_0); + iteration->IterateDiscAdj(geometry_container, solver_container, + config_container, ZONE_0, INST_0, false); /*--- Monitor the pseudo-time ---*/ @@ -275,7 +274,7 @@ void CDiscAdjSinglezoneDriver::SetRecording(RECORDING kind_recording){ /*--- Register Output of the iteration ---*/ - iteration->RegisterOutput(solver_container, geometry_container, config_container, output_container[ZONE_0], ZONE_0, INST_0); + iteration->RegisterOutput(solver_container, geometry_container, config_container, ZONE_0, INST_0); /*--- Extract the objective function and store it --- */ @@ -346,18 +345,6 @@ void CDiscAdjSinglezoneDriver::SetObjFunction(){ solver[FLOW_SOL]->SetTotal_ComboObj(0.0); -// if (config->GetnMarker_Analyze() != 0) -// output->SpecialOutput_AnalyzeSurface(solver[FLOW_SOL], geometry, config, false); - -// if ((config->GetnMarker_Analyze() != 0) && compressible) -// output->SpecialOutput_Distortion(solver[FLOW_SOL], geometry, config, false); - -// if (config->GetnMarker_NearFieldBound() != 0) -// output->SpecialOutput_SonicBoom(solver[FLOW_SOL], geometry, config, false); - -// if (config->GetPlot_Section_Forces()) -// output->SpecialOutput_SpanLoad(solver[FLOW_SOL], geometry, config, false); - /*--- Surface based obj. function ---*/ solver[FLOW_SOL]->Evaluate_ObjFunc(config); diff --git a/SU2_CFD/src/drivers/CDriver.cpp b/SU2_CFD/src/drivers/CDriver.cpp index 302e5ff3fee..677f19a7bb8 100644 --- a/SU2_CFD/src/drivers/CDriver.cpp +++ b/SU2_CFD/src/drivers/CDriver.cpp @@ -140,28 +140,22 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica nInst[iZone] = config_container[iZone]->GetnTimeInstances(); - geometry_container[iZone] = new CGeometry** [nInst[iZone]]; - iteration_container[iZone] = new CIteration* [nInst[iZone]]; - solver_container[iZone] = new CSolver*** [nInst[iZone]]; - integration_container[iZone] = new CIntegration** [nInst[iZone]]; - numerics_container[iZone] = new CNumerics**** [nInst[iZone]]; - grid_movement[iZone] = new CVolumetricMovement* [nInst[iZone]]; + geometry_container[iZone] = new CGeometry** [nInst[iZone]] (); + iteration_container[iZone] = new CIteration* [nInst[iZone]] (); + solver_container[iZone] = new CSolver*** [nInst[iZone]] (); + integration_container[iZone] = new CIntegration** [nInst[iZone]] (); + numerics_container[iZone] = new CNumerics**** [nInst[iZone]] (); + grid_movement[iZone] = new CVolumetricMovement* [nInst[iZone]] (); /*--- Allocate transfer and interpolation container --- */ interface_container[iZone] = new CInterface*[nZone] (); interpolator_container[iZone].resize(nZone); - for (iInst = 0; iInst < nInst[iZone]; iInst++){ + for (iInst = 0; iInst < nInst[iZone]; iInst++) { config_container[iZone]->SetiInst(iInst); - geometry_container[iZone][iInst] = nullptr; - iteration_container[iZone][iInst] = nullptr; - solver_container[iZone][iInst] = nullptr; - integration_container[iZone][iInst] = nullptr; - grid_movement[iZone][iInst] = nullptr; - /*--- Preprocessing of the geometry for all zones. In this routine, the edge- based data structure is constructed, i.e. node and cell neighbors are identified and linked, face areas and volumes of the dual mesh cells are @@ -235,14 +229,9 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica CGeometry::ComputeWallDistance(config_container, geometry_container); } + /*--- Definition of the interface and transfer conditions between different zones. ---*/ - /*--- Definition of the interface and transfer conditions between different zones. - *--- The transfer container is defined for zones paired one to one. - *--- This only works for a multizone FSI problem (nZone > 1). - *--- Also, at the moment this capability is limited to two zones (nZone < 3). - *--- This will change in the future. ---*/ - - if ( nZone > 1 ) { + if (nZone > 1) { if (rank == MASTER_NODE) cout << endl <<"------------------- Multizone Interface Preprocessing -------------------" << endl; @@ -250,9 +239,7 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica interface_types, interface_container, interpolator_container); } - if(fsi && (config_container[ZONE_0]->GetRestart() || config_container[ZONE_0]->GetDiscrete_Adjoint())){ - if (rank == MASTER_NODE)cout << endl <<"Restarting Fluid and Structural Solvers." << endl; - + if (fsi) { for (iZone = 0; iZone < nZone; iZone++) { for (iInst = 0; iInst < nInst[iZone]; iInst++){ Solver_Restart(solver_container[iZone][iInst], geometry_container[iZone][iInst], @@ -262,7 +249,9 @@ CDriver::CDriver(char* confFile, unsigned short val_nZone, SU2_Comm MPICommunica } if (config_container[ZONE_0]->GetBoolTurbomachinery()){ - if (rank == MASTER_NODE)cout << endl <<"---------------------- Turbomachinery Preprocessing ---------------------" << endl; + if (rank == MASTER_NODE) + cout << endl <<"---------------------- Turbomachinery Preprocessing ---------------------" << endl; + Turbomachinery_Preprocessing(config_container, geometry_container, solver_container, interface_container); } @@ -330,40 +319,28 @@ void CDriver::SetContainers_Null(){ interface_types = nullptr; nInst = nullptr; - /*--- Definition and of the containers for all possible zones. ---*/ - iteration_container = new CIteration**[nZone]; - solver_container = new CSolver****[nZone]; - integration_container = new CIntegration***[nZone]; - numerics_container = new CNumerics*****[nZone]; - config_container = new CConfig*[nZone]; - geometry_container = new CGeometry***[nZone]; - surface_movement = new CSurfaceMovement*[nZone]; - grid_movement = new CVolumetricMovement**[nZone]; - FFDBox = new CFreeFormDefBox**[nZone]; + iteration_container = new CIteration**[nZone] (); + solver_container = new CSolver****[nZone] (); + integration_container = new CIntegration***[nZone] (); + numerics_container = new CNumerics*****[nZone] (); + config_container = new CConfig*[nZone] (); + geometry_container = new CGeometry***[nZone] (); + surface_movement = new CSurfaceMovement*[nZone] (); + grid_movement = new CVolumetricMovement**[nZone] (); + FFDBox = new CFreeFormDefBox**[nZone] (); interpolator_container.resize(nZone); - interface_container = new CInterface**[nZone]; - interface_types = new unsigned short*[nZone]; - output_container = new COutput*[nZone]; - nInst = new unsigned short[nZone]; + interface_container = new CInterface**[nZone] (); + interface_types = new unsigned short*[nZone] (); + output_container = new COutput*[nZone] (); + nInst = new unsigned short[nZone] (); driver_config = nullptr; driver_output = nullptr; - for (iZone = 0; iZone < nZone; iZone++) { - solver_container[iZone] = nullptr; - integration_container[iZone] = nullptr; - numerics_container[iZone] = nullptr; - config_container[iZone] = nullptr; - geometry_container[iZone] = nullptr; - surface_movement[iZone] = nullptr; - grid_movement[iZone] = nullptr; - FFDBox[iZone] = nullptr; - interface_container[iZone] = nullptr; - interface_types[iZone] = new unsigned short[nZone]; - output_container[iZone] = nullptr; - nInst[iZone] = 1; + interface_types[iZone] = new unsigned short[nZone]; + nInst[iZone] = 1; } strcpy(runtime_file_name, "runtime.dat"); @@ -436,8 +413,7 @@ void CDriver::Postprocessing() { for (iZone = 0; iZone < nZone; iZone++) { if (interface_container[iZone] != nullptr) { for (unsigned short jZone = 0; jZone < nZone; jZone++) - if (interface_container[iZone][jZone] != nullptr) - delete interface_container[iZone][jZone]; + delete interface_container[iZone][jZone]; delete [] interface_container[iZone]; } } @@ -446,20 +422,17 @@ void CDriver::Postprocessing() { } if (interface_types != nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (interface_types[iZone] != nullptr) + for (iZone = 0; iZone < nZone; iZone++) delete [] interface_types[iZone]; - } delete [] interface_types; } for (iZone = 0; iZone < nZone; iZone++) { if (geometry_container[iZone] != nullptr) { for (iInst = 0; iInst < nInst[iZone]; iInst++){ - for (unsigned short iMGlevel = 0; iMGlevel < config_container[iZone]->GetnMGLevels()+1; iMGlevel++) { - if (geometry_container[iZone][iInst][iMGlevel] != nullptr) delete geometry_container[iZone][iInst][iMGlevel]; - } - if (geometry_container[iZone][iInst] != nullptr) delete [] geometry_container[iZone][iInst]; + for (unsigned short iMGlevel = 0; iMGlevel < config_container[iZone]->GetnMGLevels()+1; iMGlevel++) + delete geometry_container[iZone][iInst][iMGlevel]; + delete [] geometry_container[iZone][iInst]; } delete [] geometry_container[iZone]; } @@ -480,10 +453,9 @@ void CDriver::Postprocessing() { if (rank == MASTER_NODE) cout << "Deleted CSurfaceMovement class." << endl; for (iZone = 0; iZone < nZone; iZone++) { - for (iInst = 0; iInst < nInst[iZone]; iInst++){ - if (grid_movement[iZone][iInst] != nullptr) delete grid_movement[iZone][iInst]; - } - if (grid_movement[iZone] != nullptr) delete [] grid_movement[iZone]; + for (iInst = 0; iInst < nInst[iZone]; iInst++) + delete grid_movement[iZone][iInst]; + delete [] grid_movement[iZone]; } delete [] grid_movement; if (rank == MASTER_NODE) cout << "Deleted CVolumetricMovement class." << endl; @@ -497,11 +469,8 @@ void CDriver::Postprocessing() { /*--- Deallocate config container ---*/ if (config_container!= nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (config_container[iZone] != nullptr) { - delete config_container[iZone]; - } - } + for (iZone = 0; iZone < nZone; iZone++) + delete config_container[iZone]; delete [] config_container; } delete driver_config; @@ -513,18 +482,13 @@ void CDriver::Postprocessing() { /*--- Deallocate output container ---*/ if (output_container!= nullptr) { - for (iZone = 0; iZone < nZone; iZone++) { - if (output_container[iZone] != nullptr) { - delete output_container[iZone]; - } - } + for (iZone = 0; iZone < nZone; iZone++) + delete output_container[iZone]; delete [] output_container; } - delete driver_output; - if (rank == MASTER_NODE) cout << "Deleted COutput class." << endl; if (rank == MASTER_NODE) cout << "-------------------------------------------------------------------------" << endl; @@ -658,7 +622,7 @@ void CDriver::Geometrical_Preprocessing(CConfig* config, CGeometry **&geometry, unsigned short iMGlevel; - geometry = new CGeometry*[config->GetnMGLevels()+1]; + geometry = new CGeometry*[config->GetnMGLevels()+1] (); if (!fem_solver){ for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { @@ -756,7 +720,7 @@ void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geomet /*--- Allocate the memory of the current domain, and divide the grid between the ranks. ---*/ - geometry = new CGeometry *[config->GetnMGLevels()+1]; + geometry = new CGeometry *[config->GetnMGLevels()+1] (); /*--- Build the grid data structures using the ParMETIS coloring. ---*/ @@ -809,7 +773,7 @@ void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geomet /*--- Create the control volume structures ---*/ - if ((rank == MASTER_NODE) && (!fea)) cout << "Setting the control volume structure." << endl; + if (rank == MASTER_NODE) cout << "Setting the control volume structure." << endl; SU2_OMP_PARALLEL { geometry[MESH_0]->SetControlVolume(config, ALLOCATE); geometry[MESH_0]->SetBoundControlVolume(config, ALLOCATE); @@ -834,8 +798,10 @@ void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geomet /*--- Compute the surface curvature ---*/ - if ((rank == MASTER_NODE) && (!fea)) cout << "Compute the surface curvature." << endl; - geometry[MESH_0]->ComputeSurf_Curvature(config); + if (!fea) { + if (rank == MASTER_NODE) cout << "Compute the surface curvature." << endl; + geometry[MESH_0]->ComputeSurf_Curvature(config); + } /*--- Check for periodicity and disable MG if necessary. ---*/ @@ -892,6 +858,7 @@ void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geomet if (config->GetnMGLevels() != requestedMGlevels) { delete geometry[iMGlevel]; + geometry[iMGlevel] = nullptr; break; } @@ -902,16 +869,18 @@ void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geomet /*--- For unsteady simulations, initialize the grid volumes and coordinates for previous solutions. Loop over all zones/grids ---*/ - if ((config->GetTime_Marching() != TIME_MARCHING::STEADY) && config->GetGrid_Movement()) { + if ((config->GetTime_Marching() != TIME_MARCHING::STEADY) && config->GetDynamic_Grid()) { for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { /*--- Update cell volume ---*/ geometry[iMGlevel]->nodes->SetVolume_n(); geometry[iMGlevel]->nodes->SetVolume_nM1(); - /*--- Update point coordinates ---*/ - geometry[iMGlevel]->nodes->SetCoord_n(); - geometry[iMGlevel]->nodes->SetCoord_n1(); + if (config->GetGrid_Movement()) { + /*--- Update point coordinates ---*/ + geometry[iMGlevel]->nodes->SetCoord_n(); + geometry[iMGlevel]->nodes->SetCoord_n1(); + } } } @@ -928,13 +897,17 @@ void CDriver::Geometrical_Preprocessing_FVM(CConfig *config, CGeometry **&geomet /*--- Compute the max length. ---*/ - if ((rank == MASTER_NODE) && (!fea) && (iMGlevel == MESH_0)) cout << "Finding max control volume width." << endl; - geometry[iMGlevel]->SetMaxLength(config); + if (!fea) { + if ((rank == MASTER_NODE) && (iMGlevel == MESH_0)) + cout << "Finding max control volume width." << endl; + geometry[iMGlevel]->SetMaxLength(config); + } /*--- Communicate the number of neighbors. This is needed for some centered schemes and for multigrid in parallel. ---*/ - if ((rank == MASTER_NODE) && (size > SINGLE_NODE) && (!fea) && (iMGlevel == MESH_0)) cout << "Communicating number of neighbors." << endl; + if ((rank == MASTER_NODE) && (size > SINGLE_NODE) && (iMGlevel == MESH_0)) + cout << "Communicating number of neighbors." << endl; geometry[iMGlevel]->InitiateComms(geometry[iMGlevel], config, NEIGHBORS); geometry[iMGlevel]->CompleteComms(geometry[iMGlevel], config, NEIGHBORS); } @@ -964,7 +937,7 @@ void CDriver::Geometrical_Preprocessing_DGFEM(CConfig* config, CGeometry **&geom /*--- Allocate the memory of the current domain, and divide the grid between the ranks. ---*/ - geometry = new CGeometry *[config->GetnMGLevels()+1]; + geometry = new CGeometry *[config->GetnMGLevels()+1] (); geometry[MESH_0] = new CMeshFEM_DG(geometry_aux, config); @@ -1040,7 +1013,7 @@ void CDriver::Solver_Preprocessing(CConfig* config, CGeometry** geometry, CSolve if (rank == MASTER_NODE) cout << endl <<"-------------------- Solver Preprocessing ( Zone " << config->GetiZone() <<" ) --------------------" << endl; - solver = new CSolver**[config->GetnMGLevels()+1]; + solver = new CSolver**[config->GetnMGLevels()+1] (); for (iMesh = 0; iMesh <= config->GetnMGLevels(); iMesh++){ solver[iMesh] = CSolverFactory::CreateSolverContainer(kindSolver, config, geometry[iMesh], iMesh); @@ -1050,16 +1023,13 @@ void CDriver::Solver_Preprocessing(CConfig* config, CGeometry** geometry, CSolve DOFsPerPoint = 0; - for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++){ - if (solver[MESH_0][iSol] != nullptr){ - DOFsPerPoint += solver[MESH_0][iSol]->GetnVar(); - } - } + for (unsigned int iSol = 0; iSol < MAX_SOLS; iSol++) + if (solver[MESH_0][iSol]) DOFsPerPoint += solver[MESH_0][iSol]->GetnVar(); - bool update_geo = true; - if (config->GetFSI_Simulation()) update_geo = false; + /*--- Restart solvers, for FSI the geometry cannot be updated because the interpolation classes + * should always use the undeformed mesh (otherwise the results would not be repeatable). ---*/ - Solver_Restart(solver, geometry, config, update_geo); + if (!fsi) Solver_Restart(solver, geometry, config, true); /*--- Set up any necessary inlet profiles ---*/ @@ -1137,166 +1107,56 @@ void CDriver::Inlet_Preprocessing(CSolver ***solver, CGeometry **geometry, void CDriver::Solver_Restart(CSolver ***solver, CGeometry **geometry, CConfig *config, bool update_geo) { - bool euler, ns, turbulent, - NEMO_euler, NEMO_ns, - adj_euler, adj_ns, adj_turb, - heat, fem, fem_euler, fem_ns, fem_dg_flow, - template_solver, disc_adj, disc_adj_fem, disc_adj_turb, disc_adj_heat; - int val_iter = 0; - - /*--- Initialize some useful booleans ---*/ - - euler = false; ns = false; turbulent = false; - NEMO_euler = false; NEMO_ns = false; - adj_euler = false; adj_ns = false; adj_turb = false; - fem_euler = false; fem_ns = false; fem_dg_flow = false; - disc_adj = false; - fem = false; disc_adj_fem = false; - disc_adj_turb = false; - heat = false; disc_adj_heat = false; - template_solver = false; - /*--- Check for restarts and use the LoadRestart() routines. ---*/ - bool restart = config->GetRestart(); - bool restart_flow = config->GetRestart_Flow(); - bool no_restart = false; + const bool restart = config->GetRestart(); + const bool restart_flow = config->GetRestart_Flow(); /*--- Adjust iteration number for unsteady restarts. ---*/ - bool dual_time = ((config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || - (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND)); - bool time_stepping = config->GetTime_Marching() == TIME_MARCHING::TIME_STEPPING; - bool adjoint = (config->GetDiscrete_Adjoint() || config->GetContinuous_Adjoint()); - bool time_domain = (config->GetTime_Domain()); // Dynamic simulation (FSI). + int val_iter = 0; - if (dual_time) { - if (adjoint) val_iter = SU2_TYPE::Int(config->GetUnst_AdjointIter())-1; - else if (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) - val_iter = SU2_TYPE::Int(config->GetRestart_Iter())-1; - else val_iter = SU2_TYPE::Int(config->GetRestart_Iter())-2; - } + const bool adjoint = (config->GetDiscrete_Adjoint() || config->GetContinuous_Adjoint()); + const bool time_domain = config->GetTime_Domain(); + const bool dt_step_2nd = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND) && + !config->GetStructuralProblem() && !config->GetFEMSolver() && + !adjoint && time_domain; - if (time_stepping) { - if (adjoint) val_iter = SU2_TYPE::Int(config->GetUnst_AdjointIter())-1; - else val_iter = SU2_TYPE::Int(config->GetRestart_Iter())-1; + if (time_domain) { + if (adjoint) val_iter = config->GetUnst_AdjointIter() - 1; + else val_iter = config->GetRestart_Iter() - 1 - dt_step_2nd; } - /*--- Assign booleans ---*/ - - switch (config->GetKind_Solver()) { - case TEMPLATE_SOLVER: template_solver = true; break; - case EULER : case INC_EULER: euler = true; break; - case NEMO_EULER : NEMO_euler = true; break; - case NAVIER_STOKES: case INC_NAVIER_STOKES: ns = true; heat = config->GetWeakly_Coupled_Heat(); break; - case NEMO_NAVIER_STOKES: NEMO_ns = true; break; - case RANS : case INC_RANS: ns = true; turbulent = true; heat = config->GetWeakly_Coupled_Heat(); break; - case FEM_EULER : fem_euler = true; break; - case FEM_NAVIER_STOKES: fem_ns = true; break; - case FEM_RANS : fem_ns = true; break; - case FEM_LES : fem_ns = true; break; - case HEAT_EQUATION: heat = true; break; - case FEM_ELASTICITY: fem = true; break; - case ADJ_EULER : euler = true; adj_euler = true; break; - case ADJ_NAVIER_STOKES : ns = true; turbulent = (config->GetKind_Turb_Model() != NONE); adj_ns = true; break; - case ADJ_RANS : ns = true; turbulent = true; adj_ns = true; adj_turb = (!config->GetFrozen_Visc_Cont()); break; - case DISC_ADJ_EULER: case DISC_ADJ_INC_EULER: euler = true; disc_adj = true; break; - case DISC_ADJ_NAVIER_STOKES: case DISC_ADJ_INC_NAVIER_STOKES: ns = true; disc_adj = true; heat = config->GetWeakly_Coupled_Heat(); break; - case DISC_ADJ_RANS: case DISC_ADJ_INC_RANS: ns = true; turbulent = true; disc_adj = true; disc_adj_turb = (!config->GetFrozen_Visc_Disc()); heat = config->GetWeakly_Coupled_Heat(); break; - case DISC_ADJ_FEM_EULER: fem_euler = true; disc_adj = true; break; - case DISC_ADJ_FEM_NS: fem_ns = true; disc_adj = true; break; - case DISC_ADJ_FEM_RANS: fem_ns = true; turbulent = true; disc_adj = true; disc_adj_turb = (!config->GetFrozen_Visc_Disc()); break; - case DISC_ADJ_FEM: fem = true; disc_adj_fem = true; break; - case DISC_ADJ_HEAT: heat = true; disc_adj_heat = true; break; - - } - - /*--- Determine the kind of FEM solver used for the flow. ---*/ - - switch( config->GetKind_FEM_Flow() ) { - case DG: fem_dg_flow = true; break; - } - - /*--- Load restarts for any of the active solver containers. Note that - these restart routines fill the fine grid and interpolate to all MG levels. ---*/ + /*--- Restart direct solvers. ---*/ if (restart || restart_flow) { - if (euler || ns) { - SU2_OMP_PARALLEL_(if(solver[MESH_0][FLOW_SOL]->GetHasHybridParallel())) - solver[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - END_SU2_OMP_PARALLEL - } - if (NEMO_euler || NEMO_ns) { - solver[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (turbulent) { - SU2_OMP_PARALLEL_(if(solver[MESH_0][TURB_SOL]->GetHasHybridParallel())) - solver[MESH_0][TURB_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - END_SU2_OMP_PARALLEL - } - if (config->AddRadiation()) { - solver[MESH_0][RAD_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (fem) { - if (time_domain) val_iter = SU2_TYPE::Int(config->GetRestart_Iter())-1; - solver[MESH_0][FEA_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (fem_euler || fem_ns) { - if (fem_dg_flow) - solver[MESH_0][FLOW_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (heat) { - solver[MESH_0][HEAT_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); + for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) { + auto sol = solver[MESH_0][iSol]; + if (sol && !sol->GetAdjoint()) { + /*--- Note that the mesh solver always loads the most recent file (and not -2). ---*/ + SU2_OMP_PARALLEL_(if(sol->GetHasHybridParallel())) + sol->LoadRestart(geometry, solver, config, val_iter + (iSol==MESH_SOL && dt_step_2nd), update_geo); + END_SU2_OMP_PARALLEL + } } } + /*--- Restart adjoint solvers. ---*/ + if (restart) { - if (template_solver) { - no_restart = true; - } - if (heat) { - solver[MESH_0][HEAT_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (adj_euler || adj_ns) { - solver[MESH_0][ADJFLOW_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (adj_turb) { - no_restart = true; - } - if (disc_adj) { - solver[MESH_0][ADJFLOW_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - if (disc_adj_turb) - solver[MESH_0][ADJTURB_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - if (disc_adj_heat) - solver[MESH_0][ADJHEAT_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - if (config->AddRadiation()) - solver[MESH_0][ADJRAD_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - if (disc_adj_fem) { - if (time_domain) val_iter = SU2_TYPE::Int(config->GetRestart_Iter())-1; - solver[MESH_0][ADJFEA_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); + if ((config->GetKind_Solver() == TEMPLATE_SOLVER) || + (config->GetKind_Solver() == ADJ_RANS && !config->GetFrozen_Visc_Cont())) { + SU2_MPI::Error("A restart capability has not been implemented yet for this solver.\n" + "Please set RESTART_SOL= NO and try again.", CURRENT_FUNCTION); } - if (disc_adj_heat) { - solver[MESH_0][ADJHEAT_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - } - - if ((restart || restart_flow) && config->GetDeform_Mesh() && update_geo){ - /*--- Always restart with the last state ---*/ - val_iter = SU2_TYPE::Int(config->GetRestart_Iter())-1; - solver[MESH_0][MESH_SOL]->LoadRestart(geometry, solver, config, val_iter, update_geo); - } - /*--- Exit if a restart was requested for a solver that is not available. ---*/ - - if (no_restart) { - SU2_MPI::Error(string("A restart capability has not been implemented yet for this solver.\n") + - string("Please set RESTART_SOL= NO and try again."), CURRENT_FUNCTION); + for (auto iSol = 0u; iSol < MAX_SOLS; ++iSol) { + auto sol = solver[MESH_0][iSol]; + if (sol && sol->GetAdjoint()) + sol->LoadRestart(geometry, solver, config, val_iter, update_geo); + } } - /*--- Think about calls to pre / post-processing here, plus realizability checks. ---*/ - - } void CDriver::Solver_Postprocessing(CSolver ****solver, CGeometry **geometry, @@ -1355,7 +1215,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol nVar_Rad = 0, nVar_Heat = 0; - numerics = new CNumerics***[config->GetnMGLevels()+1]; + numerics = new CNumerics***[config->GetnMGLevels()+1] (); const su2double *constants = nullptr; su2double kine_Inf = 0.0, omega_Inf = 0.0; @@ -1542,9 +1402,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol numerics[iMGlevel][TEMPLATE_SOL][conv_term] = new CConvective_Template(nDim, nVar_Template, config); break; default: - SU2_OMP_MASTER SU2_MPI::Error("Convective scheme not implemented (template_solver).", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1569,9 +1427,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol /*--- Definition of the convective scheme for each equation and mesh level ---*/ switch (config->GetKind_ConvNumScheme_Flow()) { case NO_CONVECTIVE : - SU2_OMP_MASTER SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_FLOW option.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; case SPACE_CENTERED : @@ -1589,9 +1445,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol case LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLaxInc_Flow(nDim, nVar_Flow, config); break; case JST : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentJSTInc_Flow(nDim, nVar_Flow, config); break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid centered scheme or not implemented.\n Currently, only JST and LAX-FRIEDRICH are available for incompressible flows.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } for (iMGlevel = 1; iMGlevel <= config->GetnMGLevels(); iMGlevel++) @@ -1708,9 +1562,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid upwind scheme or not implemented.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1725,18 +1577,14 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol } break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid upwind scheme or not implemented.\n Currently, only FDS is available for incompressible flows.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } } break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid convective scheme for the Euler / Navier-Stokes equations.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1835,9 +1683,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol /*--- Definition of the convective scheme for each equation and mesh level ---*/ switch (config->GetKind_ConvNumScheme_Flow()) { case NO_CONVECTIVE : - SU2_OMP_MASTER SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_FLOW option.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; case SPACE_CENTERED : @@ -1846,9 +1692,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol switch (config->GetKind_Centered_Flow()) { case LAX : numerics[MESH_0][FLOW_SOL][conv_term] = new CCentLax_NEMO(nDim, nVar_NEMO, nPrimVar_NEMO, nPrimVarGrad_NEMO, config); break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid centered scheme or not implemented.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1900,9 +1744,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid upwind scheme or not implemented.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1910,9 +1752,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid convective scheme for the NEMO Euler / Navier-Stokes equations.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1982,9 +1822,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol break; default: - SU2_OMP_MASTER SU2_MPI::Error("Riemann solver not implemented.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -1998,9 +1836,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol switch (config->GetKind_ConvNumScheme_Turb()) { case NO_UPWIND: - SU2_OMP_MASTER SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_TURB option.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; case SPACE_UPWIND : for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { @@ -2011,9 +1847,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol } break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid convective scheme for the turbulence equations.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -2063,9 +1897,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol /*--- Definition of the convective scheme for each equation and mesh level ---*/ switch (config->GetKind_ConvNumScheme_Turb()) { case NO_UPWIND: - SU2_OMP_MASTER SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_TURB option.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; case SPACE_UPWIND: for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { @@ -2073,9 +1905,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol } break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid convective scheme for the transition equations.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -2118,9 +1948,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid convective scheme for the heat transfer equations.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } } @@ -2144,17 +1972,13 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol if (adj_euler || adj_ns) { if (incompressible) - SU2_OMP_MASTER SU2_MPI::Error("Convective schemes not implemented for incompressible continuous adjoint.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER /*--- Definition of the convective scheme for each equation and mesh level ---*/ switch (config->GetKind_ConvNumScheme_AdjFlow()) { case NO_CONVECTIVE: - SU2_OMP_MASTER SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_ADJFLOW option.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; case SPACE_CENTERED : @@ -2167,9 +1991,7 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol case LAX : numerics[MESH_0][ADJFLOW_SOL][conv_term] = new CCentLax_AdjFlow(nDim, nVar_Adj_Flow, config); break; case JST : numerics[MESH_0][ADJFLOW_SOL][conv_term] = new CCentJST_AdjFlow(nDim, nVar_Adj_Flow, config); break; default: - SU2_OMP_MASTER SU2_MPI::Error("Centered scheme not implemented.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -2196,18 +2018,14 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol } break; default: - SU2_OMP_MASTER SU2_MPI::Error("Upwind scheme not implemented.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } } break; default: - SU2_OMP_MASTER SU2_MPI::Error("Invalid convective scheme for the continuous adjoint Euler / Navier-Stokes equations.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -2269,25 +2087,19 @@ void CDriver::Numerics_Preprocessing(CConfig *config, CGeometry **geometry, CSol if (adj_turb) { if (!spalart_allmaras) - SU2_OMP_MASTER SU2_MPI::Error("Only the SA turbulence model can be used with the continuous adjoint solver.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER /*--- Definition of the convective scheme for each equation and mesh level ---*/ switch (config->GetKind_ConvNumScheme_AdjTurb()) { case NO_CONVECTIVE: - SU2_OMP_MASTER SU2_MPI::Error("Config file is missing the CONV_NUM_METHOD_ADJTURB option.", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; case SPACE_UPWIND : for (iMGlevel = 0; iMGlevel <= config->GetnMGLevels(); iMGlevel++) numerics[iMGlevel][ADJTURB_SOL][conv_term] = new CUpwSca_AdjTurb(nDim, nVar_Adj_Turb, config); break; default: - SU2_OMP_MASTER SU2_MPI::Error("Convective scheme not implemented (adjoint turbulence).", CURRENT_FUNCTION); - END_SU2_OMP_MASTER break; } @@ -2450,7 +2262,7 @@ void CDriver::DynamicMesh_Preprocessing(CConfig *config, CGeometry **geometry, C /*--- Update the multi-grid structure to propagate the derivative information to the coarser levels ---*/ - geometry[MESH_0]->UpdateGeometry(geometry,config); + CGeometry::UpdateGeometry(geometry,config); } @@ -2983,7 +2795,8 @@ void CFluidDriver::Run() { for (iZone = 0; iZone < nZone; iZone++) { config_container[iZone]->SetInnerIter(IntIter); - iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, solver_container, numerics_container, config_container, surface_movement, grid_movement, FFDBox, iZone, INST_0); + iteration_container[iZone][INST_0]->Iterate(output_container[iZone], integration_container, geometry_container, solver_container, numerics_container, + config_container, surface_movement, grid_movement, FFDBox, iZone, INST_0); } /*--- Check convergence in each zone --*/ diff --git a/SU2_CFD/src/drivers/CMultizoneDriver.cpp b/SU2_CFD/src/drivers/CMultizoneDriver.cpp index 50e3bbd96e4..ea5af8b5945 100644 --- a/SU2_CFD/src/drivers/CMultizoneDriver.cpp +++ b/SU2_CFD/src/drivers/CMultizoneDriver.cpp @@ -139,14 +139,11 @@ CMultizoneDriver::~CMultizoneDriver(void) { void CMultizoneDriver::StartSolver() { /*--- Find out the minimum of all references times and then set each zone to this (same) value. - * (To ensure that all zones run synchronously in time, be it a dimensional or non-dimensionalized one.) ---*/ + To ensure that all zones run synchronously in time, be it a dimensional or non-dimensionalized one. ---*/ - su2double Time_Ref = config_container[ZONE_0]->GetTime_Ref(); - - for (iZone = 1; iZone < nZone; iZone++) { - if (config_container[iZone]->GetTime_Ref() < Time_Ref) - Time_Ref = config_container[iZone]->GetTime_Ref(); - } + su2double Time_Ref = std::numeric_limits::max(); + for (iZone = 0; iZone < nZone; iZone++) + Time_Ref = min(Time_Ref, config_container[iZone]->GetTime_Ref()); for (iZone = 0; iZone < nZone; iZone++) { @@ -239,12 +236,12 @@ void CMultizoneDriver::Preprocess(unsigned long TimeIter) { /*--- Set the initial condition for EULER/N-S/RANS ---------------------------------------------*/ /*--- For FSI, the initial conditions are set, after the mesh has been moved. --------------------------------------*/ - if (!fsi && !config_container[iZone]->GetDiscrete_Adjoint() && config_container[iZone]->GetFluidProblem()) { + if (!fsi && config_container[iZone]->GetFluidProblem()) { solver_container[iZone][INST_0][MESH_0][FLOW_SOL]->SetInitialCondition(geometry_container[iZone][INST_0], solver_container[iZone][INST_0], config_container[iZone], TimeIter); } - else if (!fsi && !config_container[iZone]->GetDiscrete_Adjoint() && config_container[iZone]->GetHeatProblem()) { + else if (!fsi && config_container[iZone]->GetHeatProblem()) { /*--- Set the initial condition for HEAT equation ---------------------------------------------*/ solver_container[iZone][INST_0][MESH_0][HEAT_SOL]->SetInitialCondition(geometry_container[iZone][INST_0], solver_container[iZone][INST_0], diff --git a/SU2_CFD/src/drivers/CSinglezoneDriver.cpp b/SU2_CFD/src/drivers/CSinglezoneDriver.cpp index fd732233024..2b9f488d493 100644 --- a/SU2_CFD/src/drivers/CSinglezoneDriver.cpp +++ b/SU2_CFD/src/drivers/CSinglezoneDriver.cpp @@ -129,7 +129,7 @@ void CSinglezoneDriver::Preprocess(unsigned long TimeIter) { solver_container[ZONE_0][INST_0], config_container[ZONE_0], TimeIter); } - else if ( config_container[ZONE_0]->GetHeatProblem()) { + else if (config_container[ZONE_0]->GetHeatProblem()) { /*--- Set the initial condition for HEAT equation ---------------------------------------------*/ solver_container[ZONE_0][INST_0][MESH_0][HEAT_SOL]->SetInitialCondition(geometry_container[ZONE_0][INST_0], solver_container[ZONE_0][INST_0], @@ -164,14 +164,14 @@ void CSinglezoneDriver::Run() { void CSinglezoneDriver::Postprocess() { - iteration_container[ZONE_0][INST_0]->Postprocess(output_container[ZONE_0], integration_container, geometry_container, solver_container, - numerics_container, config_container, surface_movement, grid_movement, FFDBox, ZONE_0, INST_0); + iteration_container[ZONE_0][INST_0]->Postprocess(output_container[ZONE_0], integration_container, geometry_container, solver_container, + numerics_container, config_container, surface_movement, grid_movement, FFDBox, ZONE_0, INST_0); - /*--- A corrector step can help preventing numerical instabilities ---*/ + /*--- A corrector step can help preventing numerical instabilities ---*/ - if (config_container[ZONE_0]->GetRelaxation()) - iteration_container[ZONE_0][INST_0]->Relaxation(output_container[ZONE_0], integration_container, geometry_container, solver_container, - numerics_container, config_container, surface_movement, grid_movement, FFDBox, ZONE_0, INST_0); + if (config_container[ZONE_0]->GetRelaxation()) + iteration_container[ZONE_0][INST_0]->Relaxation(output_container[ZONE_0], integration_container, geometry_container, solver_container, + numerics_container, config_container, surface_movement, grid_movement, FFDBox, ZONE_0, INST_0); } diff --git a/SU2_CFD/src/integration/CStructuralIntegration.cpp b/SU2_CFD/src/integration/CStructuralIntegration.cpp index a82763629ff..31be9b7e8bd 100644 --- a/SU2_CFD/src/integration/CStructuralIntegration.cpp +++ b/SU2_CFD/src/integration/CStructuralIntegration.cpp @@ -212,8 +212,6 @@ void CStructuralIntegration::SetDualTime_Solver(const CGeometry *geometry, CSolv /*--- Store the solution at t+1 as solution at t, both for the local points and for the halo points ---*/ solver->GetNodes()->Set_Solution_time_n(); - solver->GetNodes()->SetSolution_Vel_time_n(); - solver->GetNodes()->SetSolution_Accel_time_n(); /*--- If FSI problem, save the last Aitken relaxation parameter of the previous time step ---*/ diff --git a/SU2_CFD/src/interfaces/cht/CConjugateHeatInterface.cpp b/SU2_CFD/src/interfaces/cht/CConjugateHeatInterface.cpp index 50baa8b386d..9996f85c410 100644 --- a/SU2_CFD/src/interfaces/cht/CConjugateHeatInterface.cpp +++ b/SU2_CFD/src/interfaces/cht/CConjugateHeatInterface.cpp @@ -40,90 +40,62 @@ void CConjugateHeatInterface::GetDonor_Variable(CSolver *donor_solution, CGeomet const CConfig *donor_config, unsigned long Marker_Donor, unsigned long Vertex_Donor, unsigned long Point_Donor) { + /*--- Compute distance of donor point to PointNormal for T-gradient/heatflux computation ---*/ const auto nDim = donor_geometry->GetnDim(); - - su2double Twall, Tnormal, dTdn, rho_cp_solid, Prandtl_Lam, laminar_viscosity, - thermal_diffusivity, thermal_conductivity=0.0, thermal_conductivityND, - heat_flux_density=0.0, conductivity_over_dist=0.0; - - /*--- Check whether the current zone is a solid zone or a fluid zone ---*/ - - const bool compressible_flow = (donor_config->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); - const bool incompressible_flow = (donor_config->GetKind_Regime() == ENUM_REGIME::INCOMPRESSIBLE) && donor_config->GetEnergy_Equation(); - const bool heat_equation = (donor_config->GetKind_Solver() == HEAT_EQUATION) || - (donor_config->GetKind_Solver() == DISC_ADJ_HEAT); - const auto Coord = donor_geometry->nodes->GetCoord(Point_Donor); const auto PointNormal = donor_geometry->vertex[Marker_Donor][Vertex_Donor]->GetNormal_Neighbor(); const auto Coord_Normal = donor_geometry->nodes->GetCoord(PointNormal); - Twall = 0.0; Tnormal = 0.0; dTdn = 0.0; - - su2double Edge_Vector[3] = {0.0}; + su2double Edge_Vector[MAXNDIM] = {0.0}; GeometryToolbox::Distance(nDim, Coord_Normal, Coord, Edge_Vector); - su2double dist = GeometryToolbox::Norm(nDim, Edge_Vector); + const su2double dist = GeometryToolbox::Norm(nDim, Edge_Vector); /*--- Retrieve temperature solution and its gradient ---*/ - if (compressible_flow) { - - Twall = donor_solution->GetNodes()->GetPrimitive(Point_Donor,0); - Tnormal = donor_solution->GetNodes()->GetPrimitive(PointNormal,0); - - dTdn = (Twall - Tnormal)/dist; - } - else if (incompressible_flow) { - - Twall = donor_solution->GetNodes()->GetTemperature(Point_Donor); - Tnormal = donor_solution->GetNodes()->GetTemperature(PointNormal); + const su2double Twall = donor_solution->GetNodes()->GetTemperature(Point_Donor); + const su2double Tnormal = donor_solution->GetNodes()->GetTemperature(PointNormal); - dTdn = (Twall - Tnormal)/dist; - } - else if (heat_equation) { - Twall = donor_solution->GetNodes()->GetSolution(Point_Donor,0); - Tnormal = donor_solution->GetNodes()->GetSolution(PointNormal,0); - - // TODO: Check if these improve accuracy, if needed at all - // const auto Normal = donor_geometry->vertex[Marker_Donor][Vertex_Donor]->GetNormal(); - // su2double Area = GeometryToolbox::Norm(nDim, Normal); - // for (iDim = 0; iDim < nDim; iDim++) { - // dTdn += (Twall - Tnormal)/dist * (Edge_Vector[iDim]/dist) * (Normal[iDim]/Area); - // } - - dTdn = (Twall - Tnormal)/dist; - } - else { + const su2double dTdn = (Twall - Tnormal)/dist; + // TODO: Check if these improve accuracy, if needed at all + // const auto Normal = donor_geometry->vertex[Marker_Donor][Vertex_Donor]->GetNormal(); + // su2double Area = GeometryToolbox::Norm(nDim, Normal); + // for (iDim = 0; iDim < nDim; iDim++) { + // dTdn += (Twall - Tnormal)/dist * (Edge_Vector[iDim]/dist) * (Normal[iDim]/Area); + // } - SU2_MPI::Error("Transfer of conjugate heat variables failed (non-supported donor solver).", CURRENT_FUNCTION); - } + /*--- Calculate the heat flux density (temperature gradient times thermal conductivity) and + thermal conductivity divided by distance. ---*/ + su2double thermal_conductivity = 0.0; + su2double heat_flux_density = 0.0; + su2double conductivity_over_dist = 0.0; - /*--- Calculate the heat flux density (temperature gradient times thermal conductivity) ---*/ + const bool compressible_flow = (donor_config->GetKind_Regime() == ENUM_REGIME::COMPRESSIBLE); + const bool incompressible_flow = (donor_config->GetKind_Regime() == ENUM_REGIME::INCOMPRESSIBLE) && donor_config->GetEnergy_Equation(); if (compressible_flow) { - su2double Gamma = donor_config->GetGamma(); - su2double Gas_Constant = donor_config->GetGas_ConstantND(); - su2double Cp = (Gamma / (Gamma - 1.0)) * Gas_Constant; + const su2double Gamma = donor_config->GetGamma(); + const su2double Gas_Constant = donor_config->GetGas_ConstantND(); + const su2double Cp = (Gamma / (Gamma - 1.0)) * Gas_Constant; - Prandtl_Lam = donor_config->GetPrandtl_Lam(); - laminar_viscosity = donor_solution->GetNodes()->GetLaminarViscosity(Point_Donor); // TDE check for consistency - Cp = (Gamma / (Gamma - 1.0)) * Gas_Constant; + const su2double Prandtl_Lam = donor_config->GetPrandtl_Lam(); + const su2double laminar_viscosity = donor_solution->GetNodes()->GetLaminarViscosity(Point_Donor); // TDE check for consistency - thermal_conductivityND = Cp*(laminar_viscosity/Prandtl_Lam); - heat_flux_density = thermal_conductivityND*dTdn; + const su2double thermal_conductivityND = Cp*(laminar_viscosity/Prandtl_Lam); + heat_flux_density = thermal_conductivityND*dTdn; if ((donor_config->GetKind_CHT_Coupling() == CHT_COUPLING::DIRECT_TEMPERATURE_ROBIN_HEATFLUX) || (donor_config->GetKind_CHT_Coupling() == CHT_COUPLING::AVERAGED_TEMPERATURE_ROBIN_HEATFLUX)) { - thermal_conductivity = thermal_conductivityND*donor_config->GetViscosity_Ref(); - conductivity_over_dist = thermal_conductivity/dist; + thermal_conductivity = thermal_conductivityND*donor_config->GetViscosity_Ref(); + conductivity_over_dist = thermal_conductivity/dist; } } else if (incompressible_flow) { const auto iPoint = donor_geometry->vertex[Marker_Donor][Vertex_Donor]->GetNode(); - thermal_conductivityND = donor_solution->GetNodes()->GetThermalConductivity(iPoint); + const su2double thermal_conductivityND = donor_solution->GetNodes()->GetThermalConductivity(iPoint); heat_flux_density = thermal_conductivityND*dTdn; if ((donor_config->GetKind_CHT_Coupling() == CHT_COUPLING::DIRECT_TEMPERATURE_ROBIN_HEATFLUX) || @@ -140,24 +112,25 @@ void CConjugateHeatInterface::GetDonor_Variable(CSolver *donor_solution, CGeomet *donor_config->GetViscosity_Ref(); break; - default: + case CONDUCTIVITYMODEL::POLYNOMIAL: + SU2_MPI::Error("Polynomial Conductivity model not implemented for CHT interface.", CURRENT_FUNCTION); break; } conductivity_over_dist = thermal_conductivity/dist; } } - else if (heat_equation) { + else if (donor_config->GetHeatProblem()) { /*--- Heat solver stand-alone case ---*/ - thermal_diffusivity = donor_config->GetThermalDiffusivity_Solid(); - heat_flux_density = thermal_diffusivity*dTdn; + const su2double thermal_diffusivity = donor_config->GetThermalDiffusivity_Solid(); + heat_flux_density = thermal_diffusivity*dTdn; if ((donor_config->GetKind_CHT_Coupling() == CHT_COUPLING::DIRECT_TEMPERATURE_ROBIN_HEATFLUX) || (donor_config->GetKind_CHT_Coupling() == CHT_COUPLING::AVERAGED_TEMPERATURE_ROBIN_HEATFLUX)) { - rho_cp_solid = donor_config->GetSpecific_Heat_Cp()*donor_config->GetDensity_Solid(); + const su2double rho_cp_solid = donor_config->GetSpecific_Heat_Cp()*donor_config->GetDensity_Solid(); conductivity_over_dist = thermal_diffusivity*rho_cp_solid/dist; } } diff --git a/SU2_CFD/src/iteration/CDiscAdjFEAIteration.cpp b/SU2_CFD/src/iteration/CDiscAdjFEAIteration.cpp index ec5cdea2892..eb1a1890a4f 100644 --- a/SU2_CFD/src/iteration/CDiscAdjFEAIteration.cpp +++ b/SU2_CFD/src/iteration/CDiscAdjFEAIteration.cpp @@ -67,40 +67,32 @@ CDiscAdjFEAIteration::~CDiscAdjFEAIteration(void) {} void CDiscAdjFEAIteration::Preprocess(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, CVolumetricMovement*** grid_movement, - CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) { + CFreeFormDefBox*** FFDBox, unsigned short iZone, unsigned short iInst) { unsigned long iPoint; - auto solvers0 = solver[val_iZone][val_iInst][MESH_0]; - auto geometry0 = geometry[val_iZone][val_iInst][MESH_0]; + auto solvers0 = solver[iZone][iInst][MESH_0]; + auto geometry0 = geometry[iZone][iInst][MESH_0]; auto dirNodes = solvers0[FEA_SOL]->GetNodes(); auto adjNodes = solvers0[ADJFEA_SOL]->GetNodes(); /*--- For the dynamic adjoint, load direct solutions from restart files. ---*/ - if (config[val_iZone]->GetTime_Domain()) { - const int TimeIter = config[val_iZone]->GetTimeIter(); - const int Direct_Iter = SU2_TYPE::Int(config[val_iZone]->GetUnst_AdjointIter()) - TimeIter - 1; + if (config[iZone]->GetTime_Domain()) { + const int TimeIter = config[iZone]->GetTimeIter(); + const int Direct_Iter = SU2_TYPE::Int(config[iZone]->GetUnst_AdjointIter()) - TimeIter - 1; /*--- We want to load the already converged solution at timesteps n and n-1 ---*/ /*--- Load solution at timestep n-1 ---*/ - LoadDynamic_Solution(geometry, solver, config, val_iZone, val_iInst, Direct_Iter - 1); + LoadDynamic_Solution(geometry, solver, config, iZone, iInst, Direct_Iter - 1); /*--- Push solution back to correct array ---*/ dirNodes->Set_Solution_time_n(); - /*--- Push solution back to correct array ---*/ - - dirNodes->SetSolution_Accel_time_n(); - - /*--- Push solution back to correct array ---*/ - - dirNodes->SetSolution_Vel_time_n(); - /*--- Load solution timestep n ---*/ - LoadDynamic_Solution(geometry, solver, config, val_iZone, val_iInst, Direct_Iter); + LoadDynamic_Solution(geometry, solver, config, iZone, iInst, Direct_Iter); /*--- Store FEA solution also in the adjoint solver in order to be able to reset it later ---*/ @@ -108,14 +100,6 @@ void CDiscAdjFEAIteration::Preprocess(COutput* output, CIntegration**** integrat adjNodes->SetSolution_Direct(iPoint, dirNodes->GetSolution(iPoint)); } - for (iPoint = 0; iPoint < geometry0->GetnPoint(); iPoint++) { - adjNodes->SetSolution_Accel_Direct(iPoint, dirNodes->GetSolution_Accel(iPoint)); - } - - for (iPoint = 0; iPoint < geometry0->GetnPoint(); iPoint++) { - adjNodes->SetSolution_Vel_Direct(iPoint, dirNodes->GetSolution_Vel(iPoint)); - } - } else { /*--- Store FEA solution also in the adjoint solver in order to be able to reset it later ---*/ @@ -124,61 +108,54 @@ void CDiscAdjFEAIteration::Preprocess(COutput* output, CIntegration**** integrat } } - solvers0[ADJFEA_SOL]->Preprocessing(geometry0, solvers0, config[val_iZone], MESH_0, 0, RUNTIME_ADJFEA_SYS, false); + solvers0[ADJFEA_SOL]->Preprocessing(geometry0, solvers0, config[iZone], MESH_0, 0, RUNTIME_ADJFEA_SYS, false); } void CDiscAdjFEAIteration::LoadDynamic_Solution(CGeometry**** geometry, CSolver***** solver, CConfig** config, - unsigned short val_iZone, unsigned short val_iInst, + unsigned short iZone, unsigned short iInst, int val_DirectIter) { unsigned short iVar; unsigned long iPoint; bool update_geo = false; // TODO: check if (val_DirectIter >= 0) { - if (rank == MASTER_NODE && val_iZone == ZONE_0) + if (rank == MASTER_NODE && iZone == ZONE_0) cout << " Loading FEA solution from direct iteration " << val_DirectIter << "." << endl; - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->LoadRestart( - geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], val_DirectIter, update_geo); + solver[iZone][iInst][MESH_0][FEA_SOL]->LoadRestart( + geometry[iZone][iInst], solver[iZone][iInst], config[iZone], val_DirectIter, update_geo); } else { /*--- If there is no solution file we set the freestream condition ---*/ - if (rank == MASTER_NODE && val_iZone == ZONE_0) + if (rank == MASTER_NODE && iZone == ZONE_0) cout << " Setting static conditions at direct iteration " << val_DirectIter << "." << endl; /*--- Push solution back to correct array ---*/ - for (iPoint = 0; iPoint < geometry[val_iZone][val_iInst][MESH_0]->GetnPoint(); iPoint++) { - for (iVar = 0; iVar < solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetnVar(); iVar++) { - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution(iPoint, iVar, 0.0); - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Accel(iPoint, iVar, 0.0); - solver[val_iZone][val_iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Vel(iPoint, iVar, 0.0); + for (iPoint = 0; iPoint < geometry[iZone][iInst][MESH_0]->GetnPoint(); iPoint++) { + for (iVar = 0; iVar < solver[iZone][iInst][MESH_0][FEA_SOL]->GetnVar(); iVar++) { + solver[iZone][iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution(iPoint, iVar, 0.0); + solver[iZone][iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Accel(iPoint, iVar, 0.0); + solver[iZone][iInst][MESH_0][FEA_SOL]->GetNodes()->SetSolution_Vel(iPoint, iVar, 0.0); } } } } -void CDiscAdjFEAIteration::Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, - CSolver***** solver, CNumerics****** numerics, CConfig** config, - CSurfaceMovement** surface_movement, CVolumetricMovement*** volume_grid_movement, - CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) { +void CDiscAdjFEAIteration::IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short iZone, unsigned short iInst, bool CrossTerm) { /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ - solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], - config[val_iZone]); + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone], + CrossTerm); - solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Variables(geometry[val_iZone][val_iInst][MESH_0], - config[val_iZone]); - if (config[val_iZone]->GetTime_Domain()) { - integration[val_iZone][val_iInst][ADJFEA_SOL]->SetConvergence(false); - } + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->ExtractAdjoint_Variables(geometry[iZone][iInst][MESH_0], config[iZone]); } void CDiscAdjFEAIteration::SetRecording(CSolver***** solver, CGeometry**** geometry, CConfig** config, - unsigned short val_iZone, unsigned short val_iInst, + unsigned short iZone, unsigned short iInst, RECORDING kind_recording) { /*--- Prepare for recording by resetting the solution to the initial converged solution ---*/ - solver[val_iZone][val_iInst][MESH_0][ADJFEA_SOL]->SetRecording(geometry[val_iZone][val_iInst][MESH_0], - config[val_iZone]); + solver[iZone][iInst][MESH_0][ADJFEA_SOL]->SetRecording(geometry[iZone][iInst][MESH_0], config[iZone]); } void CDiscAdjFEAIteration::RegisterInput(CSolver***** solver, CGeometry**** geometry, CConfig** config, @@ -198,7 +175,7 @@ void CDiscAdjFEAIteration::RegisterInput(CSolver***** solver, CGeometry**** geom /*--- Register mesh coordinates for geometric sensitivities ---*/ - geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(); } } @@ -295,10 +272,8 @@ void CDiscAdjFEAIteration::SetDependencies(CSolver***** solver, CGeometry**** ge dir_solver->InitiateComms(structural_geometry, config[iZone], SOLUTION_FEA); dir_solver->CompleteComms(structural_geometry, config[iZone], SOLUTION_FEA); - if (kind_recording == RECORDING::MESH_COORDS) { - structural_geometry->InitiateComms(structural_geometry, config[iZone], COORDINATES); - structural_geometry->CompleteComms(structural_geometry, config[iZone], COORDINATES); - } + structural_geometry->InitiateComms(structural_geometry, config[iZone], COORDINATES); + structural_geometry->CompleteComms(structural_geometry, config[iZone], COORDINATES); } END_SU2_OMP_PARALLEL @@ -339,27 +314,28 @@ void CDiscAdjFEAIteration::InitializeAdjoint(CSolver***** solver, CGeometry**** bool CDiscAdjFEAIteration::Monitor(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, CVolumetricMovement*** grid_movement, - CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) { + CFreeFormDefBox*** FFDBox, unsigned short iZone, unsigned short iInst) { /*--- Write the convergence history (only screen output) ---*/ - output->SetHistory_Output(geometry[val_iZone][INST_0][MESH_0], solver[val_iZone][INST_0][MESH_0], config[val_iZone], - config[val_iZone]->GetTimeIter(), config[val_iZone]->GetOuterIter(), - config[val_iZone]->GetInnerIter()); + output->SetHistory_Output(geometry[iZone][INST_0][MESH_0], solver[iZone][INST_0][MESH_0], config[iZone], + config[iZone]->GetTimeIter(), config[iZone]->GetOuterIter(), + config[iZone]->GetInnerIter()); return output->GetConvergence(); } + void CDiscAdjFEAIteration::Postprocess(COutput* output, CIntegration**** integration, CGeometry**** geometry, CSolver***** solver, CNumerics****** numerics, CConfig** config, CSurfaceMovement** surface_movement, CVolumetricMovement*** grid_movement, - CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) { - const bool dynamic = (config[val_iZone]->GetTime_Domain()); - auto solvers0 = solver[val_iZone][val_iInst][MESH_0]; + CFreeFormDefBox*** FFDBox, unsigned short iZone, unsigned short iInst) { + const bool dynamic = (config[iZone]->GetTime_Domain()); + auto solvers0 = solver[iZone][iInst][MESH_0]; // TEMPORARY output only for standalone structural problems - if ((!config[val_iZone]->GetFSI_Simulation()) && (rank == MASTER_NODE)) { + if (config[iZone]->GetAdvanced_FEAElementBased() && (rank == MASTER_NODE)) { unsigned short iVar; - const bool de_effects = config[val_iZone]->GetDE_Effects(); + const bool de_effects = config[iZone]->GetDE_Effects(); /*--- Header of the temporary output file ---*/ ofstream myfile_res; @@ -367,21 +343,21 @@ void CDiscAdjFEAIteration::Postprocess(COutput* output, CIntegration**** integra myfile_res.precision(15); - myfile_res << config[val_iZone]->GetTimeIter() << "\t"; + myfile_res << config[iZone]->GetTimeIter() << "\t"; - solvers0[FEA_SOL]->Evaluate_ObjFunc(config[val_iZone]); + solvers0[FEA_SOL]->Evaluate_ObjFunc(config[iZone]); myfile_res << scientific << solvers0[FEA_SOL]->GetTotal_ComboObj() << "\t"; - for (iVar = 0; iVar < config[val_iZone]->GetnElasticityMod(); iVar++) + for (iVar = 0; iVar < config[iZone]->GetnElasticityMod(); iVar++) myfile_res << scientific << solvers0[ADJFEA_SOL]->GetTotal_Sens_E(iVar) << "\t"; - for (iVar = 0; iVar < config[val_iZone]->GetnPoissonRatio(); iVar++) + for (iVar = 0; iVar < config[iZone]->GetnPoissonRatio(); iVar++) myfile_res << scientific << solvers0[ADJFEA_SOL]->GetTotal_Sens_Nu(iVar) << "\t"; if (dynamic) { - for (iVar = 0; iVar < config[val_iZone]->GetnMaterialDensity(); iVar++) + for (iVar = 0; iVar < config[iZone]->GetnMaterialDensity(); iVar++) myfile_res << scientific << solvers0[ADJFEA_SOL]->GetTotal_Sens_Rho(iVar) << "\t"; } if (de_effects) { - for (iVar = 0; iVar < config[val_iZone]->GetnElectric_Field(); iVar++) + for (iVar = 0; iVar < config[iZone]->GetnElectric_Field(); iVar++) myfile_res << scientific << solvers0[ADJFEA_SOL]->GetTotal_Sens_EField(iVar) << "\t"; } for (iVar = 0; iVar < solvers0[ADJFEA_SOL]->GetnDVFEA(); iVar++) { @@ -394,12 +370,12 @@ void CDiscAdjFEAIteration::Postprocess(COutput* output, CIntegration**** integra } // TEST: for implementation of python framework in standalone structural problems - if ((!config[val_iZone]->GetFSI_Simulation()) && (rank == MASTER_NODE)) { + if (config[iZone]->GetAdvanced_FEAElementBased() && (rank == MASTER_NODE)) { /*--- Header of the temporary output file ---*/ ofstream myfile_res; bool outputDVFEA = false; - switch (config[val_iZone]->GetDV_FEA()) { + switch (config[iZone]->GetDV_FEA()) { case YOUNG_MODULUS: myfile_res.open("grad_young.opt"); outputDVFEA = true; diff --git a/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp b/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp index ee763a6ee8f..87449a46cc4 100644 --- a/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp +++ b/SU2_CFD/src/iteration/CDiscAdjFluidIteration.cpp @@ -75,6 +75,10 @@ void CDiscAdjFluidIteration::Preprocess(COutput* output, CIntegration**** integr geometries[iMesh]->nodes->SetCoord_n(); geometries[iMesh]->nodes->SetCoord_n1(); } + if (config[iZone]->GetDynamic_Grid()) { + geometries[iMesh]->nodes->SetVolume_n(); + geometries[iMesh]->nodes->SetVolume_nM1(); + } } } if (dual_time) { @@ -96,6 +100,9 @@ void CDiscAdjFluidIteration::Preprocess(COutput* output, CIntegration**** integr if (grid_IsMoving) { geometries[iMesh]->nodes->SetCoord_n(); } + if (config[iZone]->GetDynamic_Grid()) { + geometries[iMesh]->nodes->SetVolume_n(); + } } } @@ -116,6 +123,16 @@ void CDiscAdjFluidIteration::Preprocess(COutput* output, CIntegration**** integr Afterwards the GridVelocity is computed based on the Coordinates. ---*/ + /*--- Temporarily store the loaded volumes into old containers ---*/ + if (config[iZone]->GetDynamic_Grid()) { + for (auto iMesh=0; iMesh<=config[iZone]->GetnMGLevels();iMesh++) { + geometries[iMesh]->nodes->SetVolume_Old(); + geometries[iMesh]->nodes->SetVolume_n_Old(); + geometries[iMesh]->nodes->SetVolume_nM1_Old(); + } + } + + /*-- Load mesh solver ---*/ if (config[iZone]->GetDeform_Mesh()) { solvers0[MESH_SOL]->LoadRestart(geometries, solver[iZone][iInst], config[iZone], Direct_Iter, true); } @@ -125,6 +142,26 @@ void CDiscAdjFluidIteration::Preprocess(COutput* output, CIntegration**** integr LoadUnsteady_Solution(geometry, solver, config, iInst, iZone, Direct_Iter - 1); } else { LoadUnsteady_Solution(geometry, solver, config, iInst, iZone, Direct_Iter - 2); + + /*--- Set volumes into correct containers ---*/ + if (config[iZone]->GetDynamic_Grid()) { + for (auto iMesh=0; iMesh<=config[iZone]->GetnMGLevels();iMesh++) { + /*--- If negative iteration number, set default ---*/ + if (Direct_Iter - 2 < 0) { + for(auto iPoint=0ul; iPointGetnPoint();iPoint++) { + geometries[iMesh]->nodes->SetVolume(iPoint,0.0); + } + } + + /*--- Set currently loaded volume to Volume_nM1 ---*/ + geometries[iMesh]->nodes->SetVolume_n(); + geometries[iMesh]->nodes->SetVolume_nM1(); + + /*--- Set Volume_n and Volume from old containers ---*/ + geometries[iMesh]->nodes->SetVolume_n_from_OldnM1(); + geometries[iMesh]->nodes->SetVolume_from_Oldn(); + } + } } /*--- Temporarily store the loaded solution in the Solution_Old array ---*/ @@ -330,28 +367,26 @@ void CDiscAdjFluidIteration::LoadUnsteady_Solution(CGeometry**** geometry, CSolv } } -void CDiscAdjFluidIteration::Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, - CSolver***** solver, CNumerics****** numerics, CConfig** config, - CSurfaceMovement** surface_movement, CVolumetricMovement*** volume_grid_movement, - CFreeFormDefBox*** FFDBox, unsigned short iZone, unsigned short iInst) { +void CDiscAdjFluidIteration::IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short iZone, unsigned short iInst, bool CrossTerm) { SU2_OMP_PARALLEL_(if(solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->GetHasHybridParallel())) { /*--- Extract the adjoints of the conservative input variables and store them for the next iteration ---*/ if (config[iZone]->GetFluidProblem()) { - solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone]); + solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone], CrossTerm); solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->ExtractAdjoint_Variables(geometry[iZone][iInst][MESH_0], config[iZone]); } if (turbulent && !config[iZone]->GetFrozen_Visc_Disc()) { - solver[iZone][iInst][MESH_0][ADJTURB_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone]); + solver[iZone][iInst][MESH_0][ADJTURB_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone], CrossTerm); } if (config[iZone]->GetWeakly_Coupled_Heat()) { - solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone]); + solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone], CrossTerm); } if (config[iZone]->AddRadiation()) { - solver[iZone][iInst][MESH_0][ADJRAD_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone]); + solver[iZone][iInst][MESH_0][ADJRAD_SOL]->ExtractAdjoint_Solution(geometry[iZone][iInst][MESH_0], config[iZone], CrossTerm); solver[iZone][iInst][MESH_0][ADJRAD_SOL]->ExtractAdjoint_Variables(geometry[iZone][iInst][MESH_0], config[iZone]); } @@ -383,7 +418,7 @@ void CDiscAdjFluidIteration::InitializeAdjoint(CSolver***** solver, CGeometry*** solver[iZone][iInst][MESH_0][ADJRAD_SOL]->SetAdjoint_Output(geometry[iZone][iInst][MESH_0], config[iZone]); } - if (config[iZone]->GetFluidProblem()) { + if (config[iZone]->GetFluidProblem() && config[iZone]->GetSinglezone_Driver()) { solver[iZone][iInst][MESH_0][FLOW_SOL]->SetVertexTractionsAdjoint(geometry[iZone][iInst][MESH_0], config[iZone]); } @@ -421,10 +456,9 @@ void CDiscAdjFluidIteration::RegisterInput(CSolver***** solver, CGeometry**** ge if (kind_recording == RECORDING::MESH_COORDS) { /*--- Register node coordinates as input ---*/ - geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(); } - /*--- Register the variables of the mesh deformation ---*/ if (kind_recording == RECORDING::MESH_DEFORM) { /*--- Undeformed mesh coordinates ---*/ solver[iZone][iInst][MESH_0][ADJMESH_SOL]->RegisterSolution(geometry[iZone][iInst][MESH_0], config[iZone]); @@ -432,7 +466,6 @@ void CDiscAdjFluidIteration::RegisterInput(CSolver***** solver, CGeometry**** ge /*--- Boundary displacements ---*/ solver[iZone][iInst][MESH_0][ADJMESH_SOL]->RegisterVariables(geometry[iZone][iInst][MESH_0], config[iZone]); } - } END_SU2_OMP_PARALLEL } @@ -470,7 +503,7 @@ void CDiscAdjFluidIteration::SetDependencies(CSolver***** solver, CGeometry**** (kind_recording == RECORDING::SOLUTION_AND_MESH)) { /*--- Update geometry to get the influence on other geometry variables (normals, volume etc) ---*/ - geometry[iZone][iInst][MESH_0]->UpdateGeometry(geometry[iZone][iInst], config[iZone]); + CGeometry::UpdateGeometry(geometry[iZone][iInst], config[iZone]); CGeometry::ComputeWallDistance(config, geometry); } @@ -511,7 +544,7 @@ void CDiscAdjFluidIteration::SetDependencies(CSolver***** solver, CGeometry**** } void CDiscAdjFluidIteration::RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, - COutput* output, unsigned short iZone, unsigned short iInst) { + unsigned short iZone, unsigned short iInst) { SU2_OMP_PARALLEL_(if(solver[iZone][iInst][MESH_0][ADJFLOW_SOL]->GetHasHybridParallel())) { @@ -529,7 +562,7 @@ void CDiscAdjFluidIteration::RegisterOutput(CSolver***** solver, CGeometry**** g if (config[iZone]->AddRadiation()) { solver[iZone][iInst][MESH_0][ADJRAD_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0], config[iZone]); } - if (config[iZone]->GetFluidProblem()) { + if (config[iZone]->GetFluidProblem() && config[iZone]->GetSinglezone_Driver()) { solver[iZone][iInst][MESH_0][FLOW_SOL]->RegisterVertexTractions(geometry[iZone][iInst][MESH_0], config[iZone]); } diff --git a/SU2_CFD/src/iteration/CDiscAdjHeatIteration.cpp b/SU2_CFD/src/iteration/CDiscAdjHeatIteration.cpp index b622bead93e..be710ab4b2e 100644 --- a/SU2_CFD/src/iteration/CDiscAdjHeatIteration.cpp +++ b/SU2_CFD/src/iteration/CDiscAdjHeatIteration.cpp @@ -161,13 +161,11 @@ void CDiscAdjHeatIteration::LoadUnsteady_Solution(CGeometry**** geometry, CSolve } } -void CDiscAdjHeatIteration::Iterate(COutput* output, CIntegration**** integration, CGeometry**** geometry, - CSolver***** solver, CNumerics****** numerics, CConfig** config, - CSurfaceMovement** surface_movement, CVolumetricMovement*** volume_grid_movement, - CFreeFormDefBox*** FFDBox, unsigned short val_iZone, unsigned short val_iInst) { +void CDiscAdjHeatIteration::IterateDiscAdj(CGeometry**** geometry, CSolver***** solver, CConfig** config, + unsigned short val_iZone, unsigned short val_iInst, bool CrossTerm) { solver[val_iZone][val_iInst][MESH_0][ADJHEAT_SOL]->ExtractAdjoint_Solution(geometry[val_iZone][val_iInst][MESH_0], - config[val_iZone]); + config[val_iZone], CrossTerm); } void CDiscAdjHeatIteration::InitializeAdjoint(CSolver***** solver, CGeometry**** geometry, CConfig** config, @@ -190,7 +188,7 @@ void CDiscAdjHeatIteration::RegisterInput(CSolver***** solver, CGeometry**** geo else if (kind_recording == RECORDING::MESH_COORDS) { /*--- Register node coordinates as input ---*/ - geometry[iZone][iInst][MESH_0]->RegisterCoordinates(config[iZone]); + geometry[iZone][iInst][MESH_0]->RegisterCoordinates(); } else if (kind_recording == RECORDING::MESH_DEFORM) { /*--- Register the variables of the mesh deformation ---*/ @@ -214,7 +212,7 @@ void CDiscAdjHeatIteration::SetDependencies(CSolver***** solver, CGeometry**** g (kind_recording == RECORDING::SOLUTION_AND_MESH)) { /*--- Update geometry to get the influence on other geometry variables (normals, volume etc) ---*/ - geometries[MESH_0]->UpdateGeometry(geometries, config[iZone]); + CGeometry::UpdateGeometry(geometries, config[iZone]); CGeometry::ComputeWallDistance(config, geometry); } @@ -229,7 +227,7 @@ void CDiscAdjHeatIteration::SetDependencies(CSolver***** solver, CGeometry**** g } void CDiscAdjHeatIteration::RegisterOutput(CSolver***** solver, CGeometry**** geometry, CConfig** config, - COutput* output, unsigned short iZone, unsigned short iInst) { + unsigned short iZone, unsigned short iInst) { solver[iZone][iInst][MESH_0][ADJHEAT_SOL]->RegisterOutput(geometry[iZone][iInst][MESH_0], config[iZone]); } diff --git a/SU2_CFD/src/iteration/CFluidIteration.cpp b/SU2_CFD/src/iteration/CFluidIteration.cpp index 9c215ea3b7d..dccc2149752 100644 --- a/SU2_CFD/src/iteration/CFluidIteration.cpp +++ b/SU2_CFD/src/iteration/CFluidIteration.cpp @@ -40,7 +40,7 @@ void CFluidIteration::Preprocess(COutput* output, CIntegration**** integration, /*--- Set the initial condition for FSI problems with subiterations ---*/ /*--- This is done only in the first block subiteration.---*/ /*--- From then on, the solver reuses the partially converged solution obtained in the previous subiteration ---*/ - if (fsi && (OuterIter == 0)) { + if (fsi && !config[val_iZone]->GetDiscrete_Adjoint() && (OuterIter == 0)) { solver[val_iZone][val_iInst][MESH_0][FLOW_SOL]->SetInitialCondition( geometry[val_iZone][val_iInst], solver[val_iZone][val_iInst], config[val_iZone], TimeIter); } @@ -353,6 +353,8 @@ void CFluidIteration::SetWind_GustField(CConfig* config, CGeometry** geometry, C su2double Physical_dt = config->GetDelta_UnstTime(); unsigned long TimeIter = config->GetTimeIter(); + if (config->GetDiscrete_Adjoint()) TimeIter = config->GetUnst_AdjointIter() - TimeIter - 1; + su2double Physical_t = TimeIter * Physical_dt; su2double Uinf = solver[MESH_0][FLOW_SOL]->GetVelocity_Inf(0); // Assumption gust moves at infinity velocity @@ -388,7 +390,7 @@ void CFluidIteration::SetWind_GustField(CConfig* config, CGeometry** geometry, C for (iPoint = 0; iPoint < geometry[iMGlevel]->GetnPoint(); iPoint++) { /*--- Reset the Grid Velocity to zero if there is no grid movement ---*/ - if (Kind_Grid_Movement == GUST) { + if (Kind_Grid_Movement == GUST && !(config->GetFSI_Simulation())) { for (iDim = 0; iDim < nDim; iDim++) geometry[iMGlevel]->nodes->SetGridVel(iPoint, iDim, 0.0); } diff --git a/SU2_CFD/src/meson.build b/SU2_CFD/src/meson.build index 53de4efdb1d..736100a1b81 100644 --- a/SU2_CFD/src/meson.build +++ b/SU2_CFD/src/meson.build @@ -21,6 +21,7 @@ su2_cfd_src += files(['output/COutputFactory.cpp', 'output/CElasticityOutput.cpp', 'output/CFlowCompOutput.cpp', 'output/CFlowCompFEMOutput.cpp', + 'output/CFVMOutput.cpp', 'output/CFlowOutput.cpp', 'output/CFlowIncOutput.cpp', 'output/CHeatOutput.cpp', @@ -55,7 +56,6 @@ su2_cfd_src += files(['variables/CIncNSVariable.cpp', 'variables/CTurbVariable.cpp', 'variables/CAdjNSVariable.cpp', 'variables/CBaselineVariable.cpp', - 'variables/CDiscAdjFEAVariable.cpp', 'variables/CDiscAdjFEABoundVariable.cpp', 'variables/CDiscAdjMeshBoundVariable.cpp', 'variables/CFEABoundVariable.cpp', diff --git a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp index 6de0576e9b6..9062cf1f04d 100644 --- a/SU2_CFD/src/numerics/flow/flow_diffusion.cpp +++ b/SU2_CFD/src/numerics/flow/flow_diffusion.cpp @@ -143,44 +143,24 @@ void CAvgGrad_Base::SetStressTensor(const su2double *val_primvar, } } -void CAvgGrad_Base::AddTauWall(const su2double *val_normal, - const su2double val_tau_wall) { +void CAvgGrad_Base::AddTauWall(const su2double *UnitNormal, + const su2double TauWall) { - unsigned short iDim, jDim; - su2double TauNormal, TauElem[3], TauTangent[3], WallShearStress, Area, UnitNormal[3]; + /*--- Compute the wall shear stress as the magnitude of the + tangential projection of the shear stress tensor. ---*/ - Area = GeometryToolbox::Norm(nDim, Normal); - - for (iDim = 0; iDim < nDim; iDim++) - UnitNormal[iDim] = val_normal[iDim]/Area; + su2double TauTangent[MAXNDIM]; + GeometryToolbox::TangentProjection(nDim, tau, UnitNormal, TauTangent); - /*--- First, compute wall shear stress as the magnitude of the wall-tangential - component of the shear stress tensor---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - TauElem[iDim] = 0.0; - for (jDim = 0; jDim < nDim; jDim++) - TauElem[iDim] += tau[iDim][jDim]*UnitNormal[jDim]; - } - - TauNormal = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - TauNormal += TauElem[iDim] * UnitNormal[iDim]; - - for (iDim = 0; iDim < nDim; iDim++) - TauTangent[iDim] = TauElem[iDim] - TauNormal * UnitNormal[iDim]; - - WallShearStress = 0.0; - for (iDim = 0; iDim < nDim; iDim++) - WallShearStress += TauTangent[iDim]*TauTangent[iDim]; - WallShearStress = sqrt(WallShearStress); + su2double WallShearStress = GeometryToolbox::Norm(nDim, TauTangent); + su2double Scale = TauWall / WallShearStress; /*--- Scale the stress tensor by the ratio of the wall shear stress - to the computed representation of the shear stress ---*/ + (from wall functions) to the one computed above. ---*/ - for (iDim = 0 ; iDim < nDim; iDim++) - for (jDim = 0 ; jDim < nDim; jDim++) - tau[iDim][jDim] = tau[iDim][jDim]*(val_tau_wall/WallShearStress); + for (auto iDim = 0u; iDim < nDim; iDim++) + for (auto jDim = 0u; jDim < nDim; jDim++) + tau[iDim][jDim] *= Scale; } void CAvgGrad_Base::SetTauJacobian(const su2double *val_Mean_PrimVar, @@ -401,7 +381,6 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) Mean_PrimVar[iVar] = 0.5*(PrimVar_i[iVar]+PrimVar_j[iVar]); } - /*--- Compute vector going from iPoint to jPoint ---*/ dist_ij_2 = 0.0; @@ -436,14 +415,12 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) dist_ij_2, nDim+1); } - /*--- Wall shear stress values (wall functions) ---*/ + /*--- Wall shear stress values (wall functions) only used if present for one but not both points (xor) ---*/ - if (TauWall_i > 0.0 && TauWall_j > 0.0) Mean_TauWall = 0.5*(TauWall_i + TauWall_j); - else if (TauWall_i > 0.0) Mean_TauWall = TauWall_i; - else if (TauWall_j > 0.0) Mean_TauWall = TauWall_j; - else Mean_TauWall = -1.0; + const int scale = (TauWall_i > 0.0) ^ (TauWall_j > 0.0); + Mean_TauWall = (max(TauWall_i,0.0) + max(TauWall_j,0.0)) * scale; - /* --- If using UQ methodology, set Reynolds Stress tensor and perform perturbation--- */ + /*--- If using UQ methodology, set Reynolds Stress tensor and perform perturbation ---*/ if (using_uq){ ComputePerturbedRSM(nDim, Eig_Val_Comp, uq_permute, uq_delta_b, uq_urlx, @@ -454,9 +431,9 @@ CNumerics::ResidualType<> CAvgGrad_Flow::ComputeResidual(const CConfig* config) /*--- Get projected flux tensor (viscous residual) ---*/ SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, - Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); if (config->GetQCR()) AddQCR(nDim, &Mean_GradPrimVar[1], tau); - if (Mean_TauWall > 0) AddTauWall(Normal, Mean_TauWall); + if (Mean_TauWall > 0) AddTauWall(UnitNormal, Mean_TauWall); SetHeatFluxVector(Mean_GradPrimVar, Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); @@ -622,8 +599,24 @@ CNumerics::ResidualType<> CAvgGradInc_Flow::ComputeResidual(const CConfig* confi dist_ij_2, nVar); } + /*--- Wall shear stress values (wall functions) only used if present for one but not both points (xor) ---*/ + + const int scale = (TauWall_i > 0.0) ^ (TauWall_j > 0.0); + Mean_TauWall = (max(TauWall_i,0.0) + max(TauWall_j,0.0)) * scale; + + /*--- If using UQ methodology, set Reynolds Stress tensor and perform perturbation ---*/ + + if (using_uq){ + ComputePerturbedRSM(nDim, Eig_Val_Comp, uq_permute, uq_delta_b, uq_urlx, + Mean_GradPrimVar+1, Mean_PrimVar[nDim+2], Mean_Eddy_Viscosity, + Mean_turb_ke, MeanPerturbedRSM); + } + /*--- Get projected flux tensor (viscous residual) ---*/ - SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); + SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, + Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); + if (config->GetQCR()) AddQCR(nDim, &Mean_GradPrimVar[1], tau); + if (Mean_TauWall > 0) AddTauWall(UnitNormal, Mean_TauWall); GetViscousIncProjFlux(Mean_GradPrimVar, Normal, Mean_Thermal_Conductivity); @@ -933,14 +926,12 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c dist_ij_2, nDim+1); } - /*--- Wall shear stress values (wall functions) ---*/ + /*--- Wall shear stress values (wall functions) only used if present for one but not both points (xor) ---*/ - if (TauWall_i > 0.0 && TauWall_j > 0.0) Mean_TauWall = 0.5*(TauWall_i + TauWall_j); - else if (TauWall_i > 0.0) Mean_TauWall = TauWall_i; - else if (TauWall_j > 0.0) Mean_TauWall = TauWall_j; - else Mean_TauWall = -1.0; + const int scale = (TauWall_i > 0.0) ^ (TauWall_j > 0.0); + Mean_TauWall = (max(TauWall_i,0.0) + max(TauWall_j,0.0)) * scale; - /* --- If using UQ methodology, set Reynolds Stress tensor and perform perturbation--- */ + /*--- If using UQ methodology, set Reynolds Stress tensor and perform perturbation ---*/ if (using_uq){ ComputePerturbedRSM(nDim, Eig_Val_Comp, uq_permute, uq_delta_b, uq_urlx, @@ -953,7 +944,7 @@ CNumerics::ResidualType<> CGeneralAvgGrad_Flow::ComputeResidual(const CConfig* c SetStressTensor(Mean_PrimVar, Mean_GradPrimVar, Mean_turb_ke, Mean_Laminar_Viscosity, Mean_Eddy_Viscosity); if (config->GetQCR()) AddQCR(nDim, &Mean_GradPrimVar[1], tau); - if (Mean_TauWall > 0) AddTauWall(Normal, Mean_TauWall); + if (Mean_TauWall > 0) AddTauWall(UnitNormal, Mean_TauWall); SetHeatFluxVector(Mean_GradPrimVar, Mean_Laminar_Viscosity, Mean_Eddy_Viscosity, Mean_Thermal_Conductivity, Mean_Cp); diff --git a/SU2_CFD/src/numerics/flow/flow_sources.cpp b/SU2_CFD/src/numerics/flow/flow_sources.cpp index b7e583757d4..24f6356f824 100644 --- a/SU2_CFD/src/numerics/flow/flow_sources.cpp +++ b/SU2_CFD/src/numerics/flow/flow_sources.cpp @@ -627,39 +627,62 @@ CNumerics::ResidualType<> CSourceWindGust::ComputeResidual(const CConfig* config u_gust = WindGust_i[0]; v_gust = WindGust_i[1]; +// w_gust = WindGust_i[2]; if (GustDir == X_DIR) { du_gust_dx = WindGustDer_i[0]; du_gust_dy = WindGustDer_i[1]; + //du_gust_dz = WindGustDer_i[2]; du_gust_dt = WindGustDer_i[2]; + dv_gust_dx = 0.0; dv_gust_dy = 0.0; + //dv_gust_dz = 0.0; dv_gust_dt = 0.0; + + //dw_gust_dx = 0.0; + //dw_gust_dy = 0.0; + //dw_gust_dz = 0.0; + //dw_gust_dt = 0.0; } else { du_gust_dx = 0.0; du_gust_dy = 0.0; + //du_gust_dz = 0.0; du_gust_dt = 0.0; dv_gust_dx = WindGustDer_i[0]; dv_gust_dy = WindGustDer_i[1]; + //dv_gust_dz = WindGustDer_i[2] dv_gust_dt = WindGustDer_i[2]; + //dw_gust_dx = 0.0; + //dw_gust_dy = 0.0; + //dw_gust_dz = 0.0; + //dw_gust_dt = 0.0; + // + } /*--- Primitive variables at point i ---*/ u = V_i[1]; v = V_i[2]; + // w = V_i[3] + p = V_i[nDim+1]; rho = V_i[nDim+2]; /*--- Source terms ---*/ smx = rho*(du_gust_dt + (u+u_gust)*du_gust_dx + (v+v_gust)*du_gust_dy); smy = rho*(dv_gust_dt + (u+u_gust)*dv_gust_dx + (v+v_gust)*dv_gust_dy); + //smz = rho*(dw_gust_dt + (u+u_gust)*dw_gust_dx + (v+v_gust)*dw_gust_dy) + (w+w_gust)*dw_gust_dz; + se = u*smx + v*smy + p*(du_gust_dx + dv_gust_dy); + //se = u*smx + v*smy + w*smz + p*(du_gust_dx + dv_gust_dy + dw_gust_dz); if (nDim == 2) { residual[0] = 0.0; residual[1] = smx*Volume; residual[2] = smy*Volume; + //residual[3] = smz*Volume; residual[3] = se*Volume; } else { SU2_MPI::Error("You should only be in the gust source term in two dimensions", CURRENT_FUNCTION); @@ -713,7 +736,7 @@ CNumerics::ResidualType<> CSourceIncStreamwise_Periodic::ComputeResidual(const C residual[nDim+1] = Volume * scalar_factor * dot_product; - /*--- If a RANS turbulence model ias used an additional source term, based on the eddy viscosity gradient is added. ---*/ + /*--- If a RANS turbulence model is used, an additional source term, based on the eddy viscosity gradient is added. ---*/ if(turbulent) { /*--- Compute a scalar factor ---*/ diff --git a/SU2_CFD/src/output/CAdjFlowCompOutput.cpp b/SU2_CFD/src/output/CAdjFlowCompOutput.cpp index 6d5db2133b2..c5bb5d16ff5 100644 --- a/SU2_CFD/src/output/CAdjFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CAdjFlowCompOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_adj_flow_comp.cpp + * \file CAdjFlowCompOutput.cpp * \brief Main subroutines for flow discrete adjoint output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -26,7 +26,7 @@ */ -#include "../../include/output/CAdjFlowOutput.hpp" +#include "../../include/output/CAdjFlowCompOutput.hpp" #include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solvers/CSolver.hpp" @@ -460,7 +460,7 @@ void CAdjFlowCompOutput::LoadSurfaceData(CConfig *config, CGeometry *geometry, C } -bool CAdjFlowCompOutput::SetInit_Residuals(CConfig *config){ +bool CAdjFlowCompOutput::SetInit_Residuals(const CConfig *config){ return ((config->GetTime_Marching() != TIME_MARCHING::STEADY) && (curInnerIter == 0)) || ((config->GetTime_Marching() == TIME_MARCHING::STEADY) && (curInnerIter < 2)); diff --git a/SU2_CFD/src/output/CAdjFlowIncOutput.cpp b/SU2_CFD/src/output/CAdjFlowIncOutput.cpp index f51f0e6c795..c96e0a54b4a 100644 --- a/SU2_CFD/src/output/CAdjFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CAdjFlowIncOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_adj_flow_inc.cpp + * \file CAdjFlowIncOutput.cpp * \brief Main subroutines for flow discrete adjoint output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -524,7 +524,7 @@ void CAdjFlowIncOutput::LoadSurfaceData(CConfig *config, CGeometry *geometry, CS } -bool CAdjFlowIncOutput::SetInit_Residuals(CConfig *config){ +bool CAdjFlowIncOutput::SetInit_Residuals(const CConfig *config){ return (config->GetTime_Marching() != TIME_MARCHING::STEADY && (curInnerIter == 0))|| (config->GetTime_Marching() == TIME_MARCHING::STEADY && (curTimeIter < 2)); diff --git a/SU2_CFD/src/output/CAdjHeatOutput.cpp b/SU2_CFD/src/output/CAdjHeatOutput.cpp index 3c3cbd0cabd..0570f97ad68 100644 --- a/SU2_CFD/src/output/CAdjHeatOutput.cpp +++ b/SU2_CFD/src/output/CAdjHeatOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_adj_heat.cpp + * \file CAdjHeatOutput.cpp * \brief Main subroutines for flow discrete adjoint output * \author R. Sanchez * \version 7.1.1 "Blackbird" diff --git a/SU2_CFD/src/output/CBaselineOutput.cpp b/SU2_CFD/src/output/CBaselineOutput.cpp index a37004c092f..253ac5d432b 100644 --- a/SU2_CFD/src/output/CBaselineOutput.cpp +++ b/SU2_CFD/src/output/CBaselineOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_baseline.cpp + * \file CBaselineOutput.cpp * \brief Main subroutines for flow discrete adjoint output * \author R. Sanchez * \version 7.1.1 "Blackbird" diff --git a/SU2_CFD/src/output/CElasticityOutput.cpp b/SU2_CFD/src/output/CElasticityOutput.cpp index 55d2f9f84a0..1ecc83330b2 100644 --- a/SU2_CFD/src/output/CElasticityOutput.cpp +++ b/SU2_CFD/src/output/CElasticityOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_elasticity.cpp + * \file CElasticityOutput.cpp * \brief Main subroutines for FEA output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -265,7 +265,7 @@ void CElasticityOutput::SetVolumeOutputFields(CConfig *config){ } } -bool CElasticityOutput::SetInit_Residuals(CConfig *config){ +bool CElasticityOutput::SetInit_Residuals(const CConfig *config){ return (config->GetTime_Domain() == NO && (curInnerIter == 0)); diff --git a/SU2_CFD/src/output/CFVMOutput.cpp b/SU2_CFD/src/output/CFVMOutput.cpp new file mode 100644 index 00000000000..364f1f357eb --- /dev/null +++ b/SU2_CFD/src/output/CFVMOutput.cpp @@ -0,0 +1,79 @@ +/*! + * \file CFVMOutput.cpp + * \brief Main subroutines for Finite Volume Method output + * \author T. Kattmann + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, 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/output/CFVMOutput.hpp" +#include "../../../Common/include/geometry/CGeometry.hpp" + + +CFVMOutput::CFVMOutput(CConfig *config, unsigned short nDim, bool fem_output) : COutput (config, nDim, fem_output){ } + +void CFVMOutput::AddCoordinates() { + + // Grid coordinates + AddVolumeOutput("COORD-X", "x", "COORDINATES", "x-component of the coordinate vector"); + AddVolumeOutput("COORD-Y", "y", "COORDINATES", "y-component of the coordinate vector"); + if (nDim == 3) + AddVolumeOutput("COORD-Z", "z", "COORDINATES", "z-component of the coordinate vector"); +} + + +void CFVMOutput::AddCommonFVMOutputs(const CConfig *config) { + + // Mesh quality metrics + AddVolumeOutput("ORTHOGONALITY", "Orthogonality", "MESH_QUALITY", "Orthogonality Angle (deg.)"); + AddVolumeOutput("ASPECT_RATIO", "Aspect_Ratio", "MESH_QUALITY", "CV Face Area Aspect Ratio"); + AddVolumeOutput("VOLUME_RATIO", "Volume_Ratio", "MESH_QUALITY", "CV Sub-Volume Ratio"); + + AddVolumeOutput("RANK", "rank", "MPI", "Rank of the MPI-partition"); + + for (auto iMesh = 1u; iMesh <= config->GetnMGLevels(); ++iMesh) { + stringstream key, name; + key << "MG_" << iMesh; + name << "Coarse_Grid_" << iMesh; + AddVolumeOutput(key.str(), name.str(), "MULTIGRID", "Coarse mesh"); + } +} + +void CFVMOutput::LoadCommonFVMOutputs(const CConfig* config, const CGeometry* geometry, unsigned long iPoint) { + + // Mesh quality metrics, computed in CPhysicalGeometry::ComputeMeshQualityStatistics. + if (config->GetWrt_MeshQuality()) { + SetVolumeOutputValue("ORTHOGONALITY", iPoint, geometry->Orthogonality[iPoint]); + SetVolumeOutputValue("ASPECT_RATIO", iPoint, geometry->Aspect_Ratio[iPoint]); + SetVolumeOutputValue("VOLUME_RATIO", iPoint, geometry->Volume_Ratio[iPoint]); + } + + SetVolumeOutputValue("RANK", iPoint, rank); + + if (config->GetWrt_MultiGrid()) { + for (auto iMesh = 1u; iMesh <= config->GetnMGLevels(); ++iMesh) { + stringstream key; + key << "MG_" << iMesh; + SetVolumeOutputValue(key.str(), iPoint, geometry->CoarseGridColor(iPoint,iMesh-1)); + } + } +} diff --git a/SU2_CFD/src/output/CFlowCompFEMOutput.cpp b/SU2_CFD/src/output/CFlowCompFEMOutput.cpp index 91cade8a86c..3fba86dfbd1 100644 --- a/SU2_CFD/src/output/CFlowCompFEMOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompFEMOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_flow_comp_fem.cpp + * \file CFlowCompFEMOutput.cpp * \brief Main subroutines for compressible flow output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -272,7 +272,7 @@ void CFlowCompFEMOutput::LoadHistoryData(CConfig *config, CGeometry *geometry, C } -bool CFlowCompFEMOutput::SetInit_Residuals(CConfig *config){ +bool CFlowCompFEMOutput::SetInit_Residuals(const CConfig *config){ return (config->GetTime_Marching() != TIME_MARCHING::STEADY && (curInnerIter == 0))|| (config->GetTime_Marching() == TIME_MARCHING::STEADY && (curTimeIter < 2)); diff --git a/SU2_CFD/src/output/CFlowCompOutput.cpp b/SU2_CFD/src/output/CFlowCompOutput.cpp index 077aa5b988f..f4bf29ed537 100644 --- a/SU2_CFD/src/output/CFlowCompOutput.cpp +++ b/SU2_CFD/src/output/CFlowCompOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_flow_comp.cpp + * \file CFlowCompOutput.cpp * \brief Main subroutines for compressible flow output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -34,7 +34,6 @@ CFlowCompOutput::CFlowCompOutput(CConfig *config, unsigned short nDim) : CFlowOutput(config, nDim, false) { turb_model = config->GetKind_Turb_Model(); - lastInnerIter = curInnerIter; gridMovement = config->GetDynamic_Grid(); /*--- Set the default history fields if nothing is set in the config file ---*/ @@ -58,10 +57,17 @@ CFlowCompOutput::CFlowCompOutput(CConfig *config, unsigned short nDim) : CFlowOu requestedVolumeFields.emplace_back("COORDINATES"); requestedVolumeFields.emplace_back("SOLUTION"); requestedVolumeFields.emplace_back("PRIMITIVE"); - if (gridMovement) requestedVolumeFields.emplace_back("GRID_VELOCITY"); nRequestedVolumeFields = requestedVolumeFields.size(); } + if (gridMovement) { + auto notFound = requestedVolumeFields.end(); + if (find(requestedVolumeFields.begin(), notFound, string("GRID_VELOCITY")) == notFound) { + requestedVolumeFields.emplace_back("GRID_VELOCITY"); + nRequestedVolumeFields ++; + } + } + stringstream ss; ss << "Zone " << config->GetiZone() << " (Comp. Fluid)"; multiZoneHeaderString = ss.str(); @@ -98,10 +104,6 @@ CFlowCompOutput::CFlowCompOutput(CConfig *config, unsigned short nDim) : CFlowOu } } -CFlowCompOutput::~CFlowCompOutput(void) {} - - - void CFlowCompOutput::SetHistoryOutputFields(CConfig *config){ @@ -284,10 +286,7 @@ void CFlowCompOutput::SetHistoryOutputFields(CConfig *config){ void CFlowCompOutput::SetVolumeOutputFields(CConfig *config){ // Grid coordinates - AddVolumeOutput("COORD-X", "x", "COORDINATES", "x-component of the coordinate vector"); - AddVolumeOutput("COORD-Y", "y", "COORDINATES", "y-component of the coordinate vector"); - if (nDim == 3) - AddVolumeOutput("COORD-Z", "z", "COORDINATES", "z-component of the coordinate vector"); + AddCoordinates(); // Solution variables AddVolumeOutput("DENSITY", "Density", "SOLUTION", "Density"); @@ -426,17 +425,13 @@ void CFlowCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv CVariable* Node_Flow = solver[FLOW_SOL]->GetNodes(); CVariable* Node_Turb = nullptr; + const auto Node_Geo = geometry->nodes; if (config->GetKind_Turb_Model() != NONE){ Node_Turb = solver[TURB_SOL]->GetNodes(); } - CPoint* Node_Geo = geometry->nodes; - - SetVolumeOutputValue("COORD-X", iPoint, Node_Geo->GetCoord(iPoint, 0)); - SetVolumeOutputValue("COORD-Y", iPoint, Node_Geo->GetCoord(iPoint, 1)); - if (nDim == 3) - SetVolumeOutputValue("COORD-Z", iPoint, Node_Geo->GetCoord(iPoint, 2)); + LoadCoordinates(Node_Geo->GetCoord(iPoint), iPoint); SetVolumeOutputValue("DENSITY", iPoint, Node_Flow->GetSolution(iPoint, 0)); SetVolumeOutputValue("MOMENTUM-X", iPoint, Node_Flow->GetSolution(iPoint, 1)); @@ -703,60 +698,20 @@ void CFlowCompOutput::LoadHistoryData(CConfig *config, CGeometry *geometry, CSol } -bool CFlowCompOutput::SetInit_Residuals(CConfig *config){ +bool CFlowCompOutput::SetInit_Residuals(const CConfig *config){ return (config->GetTime_Marching() != TIME_MARCHING::STEADY && (curInnerIter == 0))|| (config->GetTime_Marching() == TIME_MARCHING::STEADY && (curInnerIter < 2)); } -void CFlowCompOutput::SetAdditionalScreenOutput(CConfig *config){ +void CFlowCompOutput::SetAdditionalScreenOutput(const CConfig *config){ if (config->GetFixed_CL_Mode()){ SetFixedCLScreenOutput(config); } } -void CFlowCompOutput::SetFixedCLScreenOutput(CConfig *config){ - PrintingToolbox::CTablePrinter FixedCLSummary(&cout); - - if (fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16){ - FixedCLSummary.AddColumn("Fixed CL Mode", 40); - FixedCLSummary.AddColumn("Value", 30); - FixedCLSummary.SetAlign(PrintingToolbox::CTablePrinter::LEFT); - FixedCLSummary.PrintHeader(); - FixedCLSummary << "Current CL" << historyOutput_Map["LIFT"].value; - FixedCLSummary << "Target CL" << config->GetTarget_CL(); - FixedCLSummary << "Previous AOA" << historyOutput_Map["PREV_AOA"].value; - if (config->GetFinite_Difference_Mode()){ - FixedCLSummary << "Changed AoA by (Finite Difference step)" << historyOutput_Map["CL_DRIVER_COMMAND"].value; - lastInnerIter = curInnerIter - 1; - } - else - FixedCLSummary << "Changed AoA by" << historyOutput_Map["CL_DRIVER_COMMAND"].value; - FixedCLSummary.PrintFooter(); - SetScreen_Header(config); - } - - else if (config->GetFinite_Difference_Mode() && historyOutput_Map["AOA"].value == historyOutput_Map["PREV_AOA"].value){ - FixedCLSummary.AddColumn("Fixed CL Mode (Finite Difference)", 40); - FixedCLSummary.AddColumn("Value", 30); - FixedCLSummary.SetAlign(PrintingToolbox::CTablePrinter::LEFT); - FixedCLSummary.PrintHeader(); - FixedCLSummary << "Delta CL / Delta AoA" << config->GetdCL_dAlpha(); - FixedCLSummary << "Delta CD / Delta CL" << config->GetdCD_dCL(); - if (nDim == 3){ - FixedCLSummary << "Delta CMx / Delta CL" << config->GetdCMx_dCL(); - FixedCLSummary << "Delta CMy / Delta CL" << config->GetdCMy_dCL(); - } - FixedCLSummary << "Delta CMz / Delta CL" << config->GetdCMz_dCL(); - FixedCLSummary.PrintFooter(); - curInnerIter = lastInnerIter; - WriteMetaData(config); - curInnerIter = config->GetInnerIter(); - } -} - -bool CFlowCompOutput::WriteHistoryFile_Output(CConfig *config) { +bool CFlowCompOutput::WriteHistoryFile_Output(const CConfig *config) { return !config->GetFinite_Difference_Mode() && COutput::WriteHistoryFile_Output(config); } diff --git a/SU2_CFD/src/output/CFlowIncOutput.cpp b/SU2_CFD/src/output/CFlowIncOutput.cpp index b1b23e74c42..d688b97f85b 100644 --- a/SU2_CFD/src/output/CFlowIncOutput.cpp +++ b/SU2_CFD/src/output/CFlowIncOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_flow_inc.cpp + * \file CFlowIncOutput.cpp * \brief Main subroutines for incompressible flow output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -64,10 +64,17 @@ CFlowIncOutput::CFlowIncOutput(CConfig *config, unsigned short nDim) : CFlowOutp requestedVolumeFields.emplace_back("COORDINATES"); requestedVolumeFields.emplace_back("SOLUTION"); requestedVolumeFields.emplace_back("PRIMITIVE"); - if (gridMovement) requestedVolumeFields.emplace_back("GRID_VELOCITY"); nRequestedVolumeFields = requestedVolumeFields.size(); } + if (gridMovement) { + auto notFound = requestedVolumeFields.end(); + if (find(requestedVolumeFields.begin(), notFound, string("GRID_VELOCITY")) == notFound) { + requestedVolumeFields.emplace_back("GRID_VELOCITY"); + nRequestedVolumeFields ++; + } + } + stringstream ss; ss << "Zone " << config->GetiZone() << " (Incomp. Fluid)"; multiZoneHeaderString = ss.str(); @@ -200,7 +207,8 @@ void CFlowIncOutput::SetHistoryOutputFields(CConfig *config){ /// DESCRIPTION: Maximal heatflux AddHistoryOutput("MAXIMUM_HEATFLUX", "maxHF", ScreenOutputFormat::SCIENTIFIC, "HEAT", "Total maximum heatflux on all surfaces set with MARKER_MONITORING.", HistoryFieldType::COEFFICIENT); /// DESCRIPTION: Temperature - AddHistoryOutput("AVG_TEMPERATURE", "Temp", ScreenOutputFormat::SCIENTIFIC, "HEAT", "Total avg. temperature on all surfaces set with MARKER_MONITORING.", HistoryFieldType::COEFFICIENT); + if (heat || weakly_coupled_heat) + AddHistoryOutput("AVG_TEMPERATURE", "Temp", ScreenOutputFormat::SCIENTIFIC, "HEAT", "Total avg. temperature on all surfaces set with MARKER_MONITORING.", HistoryFieldType::COEFFICIENT); /// END_GROUP /// DESCRIPTION: Angle of attack @@ -366,10 +374,7 @@ void CFlowIncOutput::LoadHistoryData(CConfig *config, CGeometry *geometry, CSolv void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ // Grid coordinates - AddVolumeOutput("COORD-X", "x", "COORDINATES", "x-component of the coordinate vector"); - AddVolumeOutput("COORD-Y", "y", "COORDINATES", "y-component of the coordinate vector"); - if (nDim == 3) - AddVolumeOutput("COORD-Z", "z", "COORDINATES", "z-component of the coordinate vector"); + AddCoordinates(); // SOLUTION variables AddVolumeOutput("PRESSURE", "Pressure", "SOLUTION", "Pressure"); @@ -436,7 +441,7 @@ void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("RES_VELOCITY-Y", "Residual_Velocity_y", "RESIDUAL", "Residual of the y-velocity component"); if (nDim == 3) AddVolumeOutput("RES_VELOCITY-Z", "Residual_Velocity_z", "RESIDUAL", "Residual of the z-velocity component"); - if (config->GetEnergy_Equation()) + if (config->GetEnergy_Equation()) AddVolumeOutput("RES_TEMPERATURE", "Residual_Temperature", "RESIDUAL", "Residual of the temperature"); switch(config->GetKind_Turb_Model()){ @@ -458,7 +463,8 @@ void CFlowIncOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("LIMITER_VELOCITY-Y", "Limiter_Velocity_y", "LIMITER", "Limiter value of the y-velocity"); if (nDim == 3) AddVolumeOutput("LIMITER_VELOCITY-Z", "Limiter_Velocity_z", "LIMITER", "Limiter value of the z-velocity"); - AddVolumeOutput("LIMITER_TEMPERATURE", "Limiter_Temperature", "LIMITER", "Limiter value of the temperature"); + if (heat || weakly_coupled_heat) + AddVolumeOutput("LIMITER_TEMPERATURE", "Limiter_Temperature", "LIMITER", "Limiter value of the temperature"); } if (config->GetKind_SlopeLimit_Turb() != NO_LIMITER) { @@ -514,6 +520,7 @@ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolve CVariable* Node_Heat = nullptr; CVariable* Node_Turb = nullptr; CVariable* Node_Rad = nullptr; + const auto Node_Geo = geometry->nodes; if (config->GetKind_Turb_Model() != NONE){ Node_Turb = solver[TURB_SOL]->GetNodes(); @@ -522,12 +529,7 @@ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolve Node_Heat = solver[HEAT_SOL]->GetNodes(); } - CPoint* Node_Geo = geometry->nodes; - - SetVolumeOutputValue("COORD-X", iPoint, Node_Geo->GetCoord(iPoint, 0)); - SetVolumeOutputValue("COORD-Y", iPoint, Node_Geo->GetCoord(iPoint, 1)); - if (nDim == 3) - SetVolumeOutputValue("COORD-Z", iPoint, Node_Geo->GetCoord(iPoint, 2)); + LoadCoordinates(Node_Geo->GetCoord(iPoint), iPoint); SetVolumeOutputValue("PRESSURE", iPoint, Node_Flow->GetSolution(iPoint, 0)); SetVolumeOutputValue("VELOCITY-X", iPoint, Node_Flow->GetSolution(iPoint, 1)); @@ -609,12 +611,11 @@ void CFlowIncOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolve SetVolumeOutputValue("LIMITER_PRESSURE", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, 0)); SetVolumeOutputValue("LIMITER_VELOCITY-X", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, 1)); SetVolumeOutputValue("LIMITER_VELOCITY-Y", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, 2)); - if (nDim == 3){ + if (nDim == 3) SetVolumeOutputValue("LIMITER_VELOCITY-Z", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, 3)); - SetVolumeOutputValue("LIMITER_TEMPERATURE", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, 4)); - } else { - SetVolumeOutputValue("LIMITER_TEMPERATURE", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, 3)); - } + if (heat || weakly_coupled_heat) + SetVolumeOutputValue("LIMITER_TEMPERATURE", iPoint, Node_Flow->GetLimiter_Primitive(iPoint, nDim+1)); + } if (config->GetKind_SlopeLimit_Turb() != NO_LIMITER) { @@ -669,19 +670,17 @@ void CFlowIncOutput::LoadSurfaceData(CConfig *config, CGeometry *geometry, CSolv SetVolumeOutputValue("SKIN_FRICTION-Y", iPoint, solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex, 1)); if (nDim == 3) SetVolumeOutputValue("SKIN_FRICTION-Z", iPoint, solver[FLOW_SOL]->GetCSkinFriction(iMarker, iVertex, 2)); - if (weakly_coupled_heat) SetVolumeOutputValue("HEAT_FLUX", iPoint, solver[HEAT_SOL]->GetHeatFlux(iMarker, iVertex)); else { SetVolumeOutputValue("HEAT_FLUX", iPoint, solver[FLOW_SOL]->GetHeatFlux(iMarker, iVertex)); - } SetVolumeOutputValue("Y_PLUS", iPoint, solver[FLOW_SOL]->GetYPlus(iMarker, iVertex)); } } -bool CFlowIncOutput::SetInit_Residuals(CConfig *config){ +bool CFlowIncOutput::SetInit_Residuals(const CConfig *config){ return (config->GetTime_Marching() != TIME_MARCHING::STEADY && (curInnerIter == 0))|| (config->GetTime_Marching() == TIME_MARCHING::STEADY && (curInnerIter < 2)); diff --git a/SU2_CFD/src/output/CFlowOutput.cpp b/SU2_CFD/src/output/CFlowOutput.cpp index 815b400b13a..d25a861c8c4 100644 --- a/SU2_CFD/src/output/CFlowOutput.cpp +++ b/SU2_CFD/src/output/CFlowOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_flow.cpp + * \file CFlowOutput.cpp * \brief Main subroutines for compressible flow output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -30,13 +30,11 @@ #include "../../../Common/include/toolboxes/geometry_toolbox.hpp" #include "../../include/solvers/CSolver.hpp" -CFlowOutput::CFlowOutput(CConfig *config, unsigned short nDim, bool fem_output) : COutput (config, nDim, fem_output){ +CFlowOutput::CFlowOutput(CConfig *config, unsigned short nDim, bool fem_output) : CFVMOutput (config, nDim, fem_output){ + lastInnerIter = curInnerIter; } - -CFlowOutput::~CFlowOutput(void){} - void CFlowOutput::AddAnalyzeSurfaceOutput(CConfig *config){ @@ -863,7 +861,7 @@ void CFlowOutput::WriteAdditionalFiles(CConfig *config, CGeometry *geometry, CSo } -void CFlowOutput::WriteMetaData(CConfig *config){ +void CFlowOutput::WriteMetaData(const CConfig *config){ ofstream meta_file; @@ -2711,7 +2709,6 @@ void CFlowOutput::WriteForcesBreakdown(CConfig *config, CGeometry *geometry, CSo } - bool CFlowOutput::WriteVolume_Output(CConfig *config, unsigned long Iter, bool force_writing){ if (config->GetTime_Domain()){ @@ -2735,41 +2732,6 @@ bool CFlowOutput::WriteVolume_Output(CConfig *config, unsigned long Iter, bool f return false || force_writing; } -void CFlowOutput::AddCommonFVMOutputs(const CConfig *config) { - - AddVolumeOutput("ORTHOGONALITY", "Orthogonality", "MESH_QUALITY", "Orthogonality Angle (deg.)"); - AddVolumeOutput("ASPECT_RATIO", "Aspect_Ratio", "MESH_QUALITY", "CV Face Area Aspect Ratio"); - AddVolumeOutput("VOLUME_RATIO", "Volume_Ratio", "MESH_QUALITY", "CV Sub-Volume Ratio"); - - AddVolumeOutput("RANK", "rank", "MPI", "Rank of the MPI-partition"); - - for (auto iMesh = 1u; iMesh <= config->GetnMGLevels(); ++iMesh) { - stringstream key, name; - key << "MG_" << iMesh; - name << "Coarse_Grid_" << iMesh; - AddVolumeOutput(key.str(), name.str(), "MULTIGRID", "Coarse mesh"); - } -} - -void CFlowOutput::LoadCommonFVMOutputs(const CConfig* config, const CGeometry* geometry, unsigned long iPoint) { - - if (config->GetWrt_MeshQuality()) { - SetVolumeOutputValue("ORTHOGONALITY", iPoint, geometry->Orthogonality[iPoint]); - SetVolumeOutputValue("ASPECT_RATIO", iPoint, geometry->Aspect_Ratio[iPoint]); - SetVolumeOutputValue("VOLUME_RATIO", iPoint, geometry->Volume_Ratio[iPoint]); - } - - SetVolumeOutputValue("RANK", iPoint, rank); - - if (config->GetWrt_MultiGrid()) { - for (auto iMesh = 1u; iMesh <= config->GetnMGLevels(); ++iMesh) { - stringstream key; - key << "MG_" << iMesh; - SetVolumeOutputValue(key.str(), iPoint, geometry->CoarseGridColor(iPoint,iMesh-1)); - } - } -} - void CFlowOutput::SetTimeAveragedFields(){ AddVolumeOutput("MEAN_DENSITY", "MeanDensity", "TIME_AVERAGE", "Mean density"); AddVolumeOutput("MEAN_VELOCITY-X", "MeanVelocity_x", "TIME_AVERAGE", "Mean velocity x-component"); @@ -2837,3 +2799,43 @@ void CFlowOutput::LoadTimeAveragedData(unsigned long iPoint, CVariable *Node_Flo SetVolumeOutputValue("VWPRIME", iPoint, -(vmean*wmean - vwmean)); } } + +void CFlowOutput::SetFixedCLScreenOutput(const CConfig *config){ + PrintingToolbox::CTablePrinter FixedCLSummary(&cout); + + if (fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16){ + FixedCLSummary.AddColumn("Fixed CL Mode", 40); + FixedCLSummary.AddColumn("Value", 30); + FixedCLSummary.SetAlign(PrintingToolbox::CTablePrinter::LEFT); + FixedCLSummary.PrintHeader(); + FixedCLSummary << "Current CL" << historyOutput_Map["LIFT"].value; + FixedCLSummary << "Target CL" << config->GetTarget_CL(); + FixedCLSummary << "Previous AOA" << historyOutput_Map["PREV_AOA"].value; + if (config->GetFinite_Difference_Mode()){ + FixedCLSummary << "Changed AoA by (Finite Difference step)" << historyOutput_Map["CL_DRIVER_COMMAND"].value; + lastInnerIter = curInnerIter - 1; + } + else + FixedCLSummary << "Changed AoA by" << historyOutput_Map["CL_DRIVER_COMMAND"].value; + FixedCLSummary.PrintFooter(); + SetScreen_Header(config); + } + + else if (config->GetFinite_Difference_Mode() && historyOutput_Map["AOA"].value == historyOutput_Map["PREV_AOA"].value){ + FixedCLSummary.AddColumn("Fixed CL Mode (Finite Difference)", 40); + FixedCLSummary.AddColumn("Value", 30); + FixedCLSummary.SetAlign(PrintingToolbox::CTablePrinter::LEFT); + FixedCLSummary.PrintHeader(); + FixedCLSummary << "Delta CL / Delta AoA" << config->GetdCL_dAlpha(); + FixedCLSummary << "Delta CD / Delta CL" << config->GetdCD_dCL(); + if (nDim == 3){ + FixedCLSummary << "Delta CMx / Delta CL" << config->GetdCMx_dCL(); + FixedCLSummary << "Delta CMy / Delta CL" << config->GetdCMy_dCL(); + } + FixedCLSummary << "Delta CMz / Delta CL" << config->GetdCMz_dCL(); + FixedCLSummary.PrintFooter(); + curInnerIter = lastInnerIter; + WriteMetaData(config); + curInnerIter = config->GetInnerIter(); + } +} diff --git a/SU2_CFD/src/output/CHeatOutput.cpp b/SU2_CFD/src/output/CHeatOutput.cpp index 831c2afa98b..0e277da5787 100644 --- a/SU2_CFD/src/output/CHeatOutput.cpp +++ b/SU2_CFD/src/output/CHeatOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_heat.cpp + * \file CHeatOutput.cpp * \brief Main subroutines for the heat solver output * \author R. Sanchez * \version 7.1.1 "Blackbird" @@ -30,7 +30,7 @@ #include "../../../Common/include/geometry/CGeometry.hpp" #include "../../include/solvers/CSolver.hpp" -CHeatOutput::CHeatOutput(CConfig *config, unsigned short nDim) : COutput(config, nDim, false) { +CHeatOutput::CHeatOutput(CConfig *config, unsigned short nDim) : CFVMOutput(config, nDim, false) { multiZone = config->GetMultizone_Problem(); @@ -117,10 +117,7 @@ void CHeatOutput::SetHistoryOutputFields(CConfig *config){ void CHeatOutput::SetVolumeOutputFields(CConfig *config){ // Grid coordinates - AddVolumeOutput("COORD-X", "x", "COORDINATES", "x-component of the coordinate vector"); - AddVolumeOutput("COORD-Y", "y", "COORDINATES", "y-component of the coordinate vector"); - if (nDim == 3) - AddVolumeOutput("COORD-Z", "z", "COORDINATES","z-component of the coordinate vector"); + AddCoordinates(); // SOLUTION AddVolumeOutput("TEMPERATURE", "Temperature", "SOLUTION", "Temperature"); @@ -131,26 +128,17 @@ void CHeatOutput::SetVolumeOutputFields(CConfig *config){ // Residuals AddVolumeOutput("RES_TEMPERATURE", "Residual_Temperature", "RESIDUAL", "Residual of the temperature"); - // Mesh quality metrics, computed in CPhysicalGeometry::ComputeMeshQualityStatistics. - AddVolumeOutput("ORTHOGONALITY", "Orthogonality", "MESH_QUALITY", "Orthogonality Angle (deg.)"); - AddVolumeOutput("ASPECT_RATIO", "Aspect_Ratio", "MESH_QUALITY", "CV Face Area Aspect Ratio"); - AddVolumeOutput("VOLUME_RATIO", "Volume_Ratio", "MESH_QUALITY", "CV Sub-Volume Ratio"); - - // MPI-Rank - AddVolumeOutput("RANK", "rank", "MPI", "Rank of the MPI-partition"); + AddCommonFVMOutputs(config); } void CHeatOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint){ CVariable* Node_Heat = solver[HEAT_SOL]->GetNodes(); - CPoint* Node_Geo = geometry->nodes; + const auto Node_Geo = geometry->nodes; // Grid coordinates - SetVolumeOutputValue("COORD-X", iPoint, Node_Geo->GetCoord(iPoint, 0)); - SetVolumeOutputValue("COORD-Y", iPoint, Node_Geo->GetCoord(iPoint, 1)); - if (nDim == 3) - SetVolumeOutputValue("COORD-Z", iPoint, Node_Geo->GetCoord(iPoint, 2)); + LoadCoordinates(Node_Geo->GetCoord(iPoint), iPoint); // SOLUTION SetVolumeOutputValue("TEMPERATURE", iPoint, Node_Heat->GetSolution(iPoint, 0)); @@ -158,15 +146,7 @@ void CHeatOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolver * // Residuals SetVolumeOutputValue("RES_TEMPERATURE", iPoint, solver[HEAT_SOL]->LinSysRes(iPoint, 0)); - // Mesh quality metrics - if (config->GetWrt_MeshQuality()) { - SetVolumeOutputValue("ORTHOGONALITY", iPoint, geometry->Orthogonality[iPoint]); - SetVolumeOutputValue("ASPECT_RATIO", iPoint, geometry->Aspect_Ratio[iPoint]); - SetVolumeOutputValue("VOLUME_RATIO", iPoint, geometry->Volume_Ratio[iPoint]); - } - - // MPI-Rank - SetVolumeOutputValue("RANK", iPoint, rank); + LoadCommonFVMOutputs(config, geometry, iPoint); } void CHeatOutput::LoadSurfaceData(CConfig *config, CGeometry *geometry, CSolver **solver, unsigned long iPoint, unsigned short iMarker, unsigned long iVertex){ diff --git a/SU2_CFD/src/output/CMeshOutput.cpp b/SU2_CFD/src/output/CMeshOutput.cpp index ea2969ecbd2..5b27d3e7bbe 100644 --- a/SU2_CFD/src/output/CMeshOutput.cpp +++ b/SU2_CFD/src/output/CMeshOutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_mesh.cpp + * \file CMeshOutput.cpp * \brief Main subroutines for the heat solver output * \author R. Sanchez * \version 7.1.1 "Blackbird" diff --git a/SU2_CFD/src/output/CMultizoneOutput.cpp b/SU2_CFD/src/output/CMultizoneOutput.cpp index c5b6037cb0f..7042ede5adb 100644 --- a/SU2_CFD/src/output/CMultizoneOutput.cpp +++ b/SU2_CFD/src/output/CMultizoneOutput.cpp @@ -141,7 +141,7 @@ void CMultizoneOutput::SetMultizoneHistoryOutputFields(COutput **output, CConfig } } -bool CMultizoneOutput::WriteScreen_Header(CConfig *config) { +bool CMultizoneOutput::WriteScreen_Header(const CConfig *config) { /*--- Print header if the outer iteration is zero or zonal convergence is printed ---*/ @@ -157,7 +157,7 @@ bool CMultizoneOutput::WriteScreen_Header(CConfig *config) { return false; } -bool CMultizoneOutput::WriteScreen_Output(CConfig *config) { +bool CMultizoneOutput::WriteScreen_Output(const CConfig *config) { unsigned long ScreenWrt_Freq_Outer = config->GetScreen_Wrt_Freq(1); unsigned long ScreenWrt_Freq_Time = config->GetScreen_Wrt_Freq(0); @@ -183,7 +183,7 @@ bool CMultizoneOutput::WriteScreen_Output(CConfig *config) { return true; } -bool CMultizoneOutput::WriteHistoryFile_Output(CConfig *config){ +bool CMultizoneOutput::WriteHistoryFile_Output(const CConfig *config){ unsigned long HistoryWrt_Freq_Outer = config->GetHistory_Wrt_Freq(1); unsigned long HistoryWrt_Freq_Time = config->GetHistory_Wrt_Freq(0); diff --git a/SU2_CFD/src/output/CNEMOCompOutput.cpp b/SU2_CFD/src/output/CNEMOCompOutput.cpp index c3de5fbf3a5..81061fc1192 100644 --- a/SU2_CFD/src/output/CNEMOCompOutput.cpp +++ b/SU2_CFD/src/output/CNEMOCompOutput.cpp @@ -43,8 +43,7 @@ CNEMOCompOutput::CNEMOCompOutput(CConfig *config, unsigned short nDim) : CFlowOutput(config, nDim, false) { turb_model = config->GetKind_Turb_Model(); - lastInnerIter = curInnerIter; - gridMovement = config->GetGrid_Movement(); + gridMovement = config->GetDynamic_Grid(); nSpecies = config->GetnSpecies(); /*--- Set the default history fields if nothing is set in the config file ---*/ @@ -74,6 +73,14 @@ CNEMOCompOutput::CNEMOCompOutput(CConfig *config, unsigned short nDim) : CFlowOu nRequestedVolumeFields = requestedVolumeFields.size(); } + if (gridMovement) { + auto notFound = requestedVolumeFields.end(); + if (find(requestedVolumeFields.begin(), notFound, string("GRID_VELOCITY")) == notFound) { + requestedVolumeFields.emplace_back("GRID_VELOCITY"); + nRequestedVolumeFields ++; + } + } + stringstream ss; ss << "Zone " << config->GetiZone() << " (Comp. Fluid)"; multiZoneHeaderString = ss.str(); @@ -109,8 +116,6 @@ CNEMOCompOutput::CNEMOCompOutput(CConfig *config, unsigned short nDim) : CFlowOu } } -CNEMOCompOutput::~CNEMOCompOutput(void) {} - void CNEMOCompOutput::SetHistoryOutputFields(CConfig *config){ /// BEGIN_GROUP: RMS_RES, DESCRIPTION: The root-mean-square residuals of the SOLUTION variables. @@ -288,10 +293,7 @@ void CNEMOCompOutput::SetVolumeOutputFields(CConfig *config){ unsigned short nSpecies = config->GetnSpecies(); // Grid coordinates - AddVolumeOutput("COORD-X", "x", "COORDINATES", "x-component of the coordinate vector"); - AddVolumeOutput("COORD-Y", "y", "COORDINATES", "y-component of the coordinate vector"); - if (nDim == 3) - AddVolumeOutput("COORD-Z", "z", "COORDINATES", "z-component of the coordinate vector"); + AddCoordinates(); // Solution variables for(iSpecies = 0; iSpecies < nSpecies; iSpecies++) @@ -327,7 +329,7 @@ void CNEMOCompOutput::SetVolumeOutputFields(CConfig *config){ AddVolumeOutput("MASSFRAC_" + std::to_string(iSpecies), "MassFrac_" + std::to_string(iSpecies), "AUXILIARY", "MassFrac_" + std::to_string(iSpecies)); // Grid velocity - if (config->GetDynamic_Grid()){ + if (gridMovement){ AddVolumeOutput("GRID_VELOCITY-X", "Grid_Velocity_x", "GRID_VELOCITY", "x-component of the grid velocity vector"); AddVolumeOutput("GRID_VELOCITY-Y", "Grid_Velocity_y", "GRID_VELOCITY", "y-component of the grid velocity vector"); if (nDim == 3 ) @@ -431,17 +433,13 @@ void CNEMOCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv CVariable* Node_Flow = solver[FLOW_SOL]->GetNodes(); CVariable* Node_Turb = NULL; unsigned short nSpecies = config->GetnSpecies(); + const auto Node_Geo = geometry->nodes; if (config->GetKind_Turb_Model() != NONE){ Node_Turb = solver[TURB_SOL]->GetNodes(); } - auto* Node_Geo = geometry->nodes; - - SetVolumeOutputValue("COORD-X", iPoint, Node_Geo->GetCoord(iPoint, 0)); - SetVolumeOutputValue("COORD-Y", iPoint, Node_Geo->GetCoord(iPoint, 1)); - if (nDim == 3) - SetVolumeOutputValue("COORD-Z", iPoint, Node_Geo->GetCoord(iPoint, 2)); + LoadCoordinates(Node_Geo->GetCoord(iPoint), iPoint); for(iSpecies = 0; iSpecies < nSpecies; iSpecies++) SetVolumeOutputValue("DENSITY_" + std::to_string(iSpecies), iPoint, Node_Flow->GetSolution(iPoint, iSpecies)); @@ -474,7 +472,7 @@ void CNEMOCompOutput::LoadVolumeData(CConfig *config, CGeometry *geometry, CSolv break; } - if (config->GetDynamic_Grid()){ + if (gridMovement){ SetVolumeOutputValue("GRID_VELOCITY-X", iPoint, Node_Geo->GetGridVel(iPoint)[0]); SetVolumeOutputValue("GRID_VELOCITY-Y", iPoint, Node_Geo->GetGridVel(iPoint)[1]); if (nDim == 3) @@ -693,60 +691,20 @@ void CNEMOCompOutput::LoadHistoryData(CConfig *config, CGeometry *geometry, CSol } -bool CNEMOCompOutput::SetInit_Residuals(CConfig *config){ +bool CNEMOCompOutput::SetInit_Residuals(const CConfig *config){ return (config->GetTime_Marching() != TIME_MARCHING::STEADY && (curInnerIter == 0))|| (config->GetTime_Marching() == TIME_MARCHING::STEADY && (curInnerIter < 2)); } -void CNEMOCompOutput::SetAdditionalScreenOutput(CConfig *config){ +void CNEMOCompOutput::SetAdditionalScreenOutput(const CConfig *config){ if (config->GetFixed_CL_Mode()){ SetFixedCLScreenOutput(config); } } -void CNEMOCompOutput::SetFixedCLScreenOutput(CConfig *config){ - PrintingToolbox::CTablePrinter FixedCLSummary(&cout); - - if (fabs(historyOutput_Map["CL_DRIVER_COMMAND"].value) > 1e-16){ - FixedCLSummary.AddColumn("Fixed CL Mode", 40); - FixedCLSummary.AddColumn("Value", 30); - FixedCLSummary.SetAlign(PrintingToolbox::CTablePrinter::LEFT); - FixedCLSummary.PrintHeader(); - FixedCLSummary << "Current CL" << historyOutput_Map["LIFT"].value; - FixedCLSummary << "Target CL" << config->GetTarget_CL(); - FixedCLSummary << "Previous AOA" << historyOutput_Map["PREV_AOA"].value; - if (config->GetFinite_Difference_Mode()){ - FixedCLSummary << "Changed AoA by (Finite Difference step)" << historyOutput_Map["CL_DRIVER_COMMAND"].value; - lastInnerIter = curInnerIter - 1; - } - else - FixedCLSummary << "Changed AoA by" << historyOutput_Map["CL_DRIVER_COMMAND"].value; - FixedCLSummary.PrintFooter(); - SetScreen_Header(config); - } - - else if (config->GetFinite_Difference_Mode() && historyOutput_Map["AOA"].value == historyOutput_Map["PREV_AOA"].value){ - FixedCLSummary.AddColumn("Fixed CL Mode (Finite Difference)", 40); - FixedCLSummary.AddColumn("Value", 30); - FixedCLSummary.SetAlign(PrintingToolbox::CTablePrinter::LEFT); - FixedCLSummary.PrintHeader(); - FixedCLSummary << "Delta CL / Delta AoA" << config->GetdCL_dAlpha(); - FixedCLSummary << "Delta CD / Delta CL" << config->GetdCD_dCL(); - if (nDim == 3){ - FixedCLSummary << "Delta CMx / Delta CL" << config->GetdCMx_dCL(); - FixedCLSummary << "Delta CMy / Delta CL" << config->GetdCMy_dCL(); - } - FixedCLSummary << "Delta CMz / Delta CL" << config->GetdCMz_dCL(); - FixedCLSummary.PrintFooter(); - curInnerIter = lastInnerIter; - WriteMetaData(config); - curInnerIter = config->GetInnerIter(); - } -} - -bool CNEMOCompOutput::WriteHistoryFile_Output(CConfig *config) { +bool CNEMOCompOutput::WriteHistoryFile_Output(const CConfig *config) { return !config->GetFinite_Difference_Mode() && COutput::WriteHistoryFile_Output(config); } diff --git a/SU2_CFD/src/output/COutput.cpp b/SU2_CFD/src/output/COutput.cpp index efc29fe036e..c37bcab5a65 100644 --- a/SU2_CFD/src/output/COutput.cpp +++ b/SU2_CFD/src/output/COutput.cpp @@ -1,5 +1,5 @@ /*! - * \file output_structure.cpp + * \file COutput.cpp * \brief Main subroutines for output solver information * \author F. Palacios, T. Economon * \version 7.1.1 "Blackbird" @@ -980,7 +980,7 @@ bool COutput::MonitorTimeConvergence(CConfig *config, unsigned long TimeIteratio return TimeConvergence; } -void COutput::SetHistoryFile_Header(CConfig *config) { +void COutput::SetHistoryFile_Header(const CConfig *config) { unsigned short iField_Output = 0, iReqField = 0, @@ -1024,7 +1024,7 @@ void COutput::SetHistoryFile_Header(CConfig *config) { } -void COutput::SetHistoryFile_Output(CConfig *config) { +void COutput::SetHistoryFile_Output(const CConfig *config) { unsigned short iField_Output = 0, iReqField = 0, @@ -1060,14 +1060,14 @@ void COutput::SetHistoryFile_Output(CConfig *config) { histFile.flush(); } -void COutput::SetScreen_Header(CConfig *config) { +void COutput::SetScreen_Header(const CConfig *config) { if (config->GetMultizone_Problem()) multiZoneHeaderTable->PrintHeader(); convergenceTable->PrintHeader(); } -void COutput::SetScreen_Output(CConfig *config) { +void COutput::SetScreen_Output(const CConfig *config) { string RequestedField; @@ -1815,7 +1815,7 @@ void COutput::Postprocess_HistoryFields(CConfig *config){ } } -bool COutput::WriteScreen_Header(CConfig *config) { +bool COutput::WriteScreen_Header(const CConfig *config) { unsigned long RestartIter = 0; @@ -1867,7 +1867,7 @@ bool COutput::WriteScreen_Header(CConfig *config) { return false; } -bool COutput::WriteScreen_Output(CConfig *config) { +bool COutput::WriteScreen_Output(const CConfig *config) { unsigned long ScreenWrt_Freq_Inner = config->GetScreen_Wrt_Freq(2); unsigned long ScreenWrt_Freq_Outer = config->GetScreen_Wrt_Freq(1); @@ -1908,7 +1908,7 @@ bool COutput::WriteScreen_Output(CConfig *config) { } -bool COutput::WriteHistoryFile_Output(CConfig *config) { +bool COutput::WriteHistoryFile_Output(const CConfig *config) { unsigned long HistoryWrt_Freq_Inner = config->GetHistory_Wrt_Freq(2); unsigned long HistoryWrt_Freq_Outer = config->GetHistory_Wrt_Freq(1); diff --git a/SU2_CFD/src/output/COutputFactory.cpp b/SU2_CFD/src/output/COutputFactory.cpp index 2feb4cd3ac3..5814c85767b 100644 --- a/SU2_CFD/src/output/COutputFactory.cpp +++ b/SU2_CFD/src/output/COutputFactory.cpp @@ -33,7 +33,7 @@ #include "../../include/output/CAdjElasticityOutput.hpp" #include "../../include/output/CFlowCompOutput.hpp" #include "../../include/output/CNEMOCompOutput.hpp" -#include "../../include/output/CAdjFlowOutput.hpp" +#include "../../include/output/CAdjFlowCompOutput.hpp" #include "../../include/output/CFlowCompFEMOutput.hpp" #include "../../include/output/CFlowIncOutput.hpp" #include "../../include/output/CAdjFlowIncOutput.hpp" diff --git a/SU2_CFD/src/output/output_structure_legacy.cpp b/SU2_CFD/src/output/output_structure_legacy.cpp index acfa5d7f1b5..fc65caa3aeb 100644 --- a/SU2_CFD/src/output/output_structure_legacy.cpp +++ b/SU2_CFD/src/output/output_structure_legacy.cpp @@ -1,5 +1,5 @@ /*! - * \file output_structure.cpp + * \file output_structure_legacy.cpp * \brief Main subroutines for output solver information * \author F. Palacios, T. Economon * \version 7.1.1 "Blackbird" diff --git a/SU2_CFD/src/python_wrapper_structure.cpp b/SU2_CFD/src/python_wrapper_structure.cpp index 97237e680a7..588e61d43f1 100644 --- a/SU2_CFD/src/python_wrapper_structure.cpp +++ b/SU2_CFD/src/python_wrapper_structure.cpp @@ -228,7 +228,7 @@ vector CDriver::GetInitialMeshCoord(unsigned short iMarker, unsig return coord_passive; } -vector CDriver::GetVertexUnitNormal(unsigned short iMarker, unsigned long iVertex) const { +vector CDriver::GetVertexNormal(unsigned short iMarker, unsigned long iVertex, bool unitNormal) const { su2double *Normal; su2double Area; @@ -237,6 +237,15 @@ vector CDriver::GetVertexUnitNormal(unsigned short iMarker, unsig Normal = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNormal(); + if (!unitNormal) { + + ret_Normal_passive[0] = SU2_TYPE::GetValue(Normal[0]); + ret_Normal_passive[1] = SU2_TYPE::GetValue(Normal[1]); + if(nDim>2) ret_Normal_passive[2] = SU2_TYPE::GetValue(Normal[2]); + + return ret_Normal_passive; + } + Area = GeometryToolbox::Norm(nDim, Normal); ret_Normal[0] = Normal[0]/Area; @@ -806,6 +815,20 @@ void CDriver::SetSourceTerm_DispAdjoint(unsigned short iMarker, unsigned long iV } +void CDriver::SetSourceTerm_VelAdjoint(unsigned short iMarker, unsigned long iVertex, passivedouble val_AdjointX, + passivedouble val_AdjointY, passivedouble val_AdjointZ) { + + CSolver *solver = solver_container[ZONE_0][INST_0][MESH_0][ADJFEA_SOL]; + CGeometry *geometry = geometry_container[ZONE_0][INST_0][MESH_0]; + const auto iPoint = geometry_container[ZONE_0][INST_0][MESH_0]->vertex[iMarker][iVertex]->GetNode(); + + solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 0, val_AdjointX); + solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 1, val_AdjointY); + if (geometry->GetnDim() == 3) + solver->GetNodes()->SetSourceTerm_VelAdjoint(iPoint, 2, val_AdjointZ); + +} + //////////////////////////////////////////////////////////////////////////////// /* Functions related to mesh deformation */ //////////////////////////////////////////////////////////////////////////////// diff --git a/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp b/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp index 9b377b54751..3f0e634230e 100644 --- a/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjFEASolver.cpp @@ -26,7 +26,6 @@ */ #include "../../include/solvers/CDiscAdjFEASolver.hpp" -#include "../../include/variables/CDiscAdjFEAVariable.hpp" CDiscAdjFEASolver::CDiscAdjFEASolver(CGeometry *geometry, CConfig *config, CSolver *direct_solver, unsigned short Kind_Solver, unsigned short iMesh) : CSolver() { @@ -37,7 +36,7 @@ CDiscAdjFEASolver::CDiscAdjFEASolver(CGeometry *geometry, CConfig *config, CSolv const bool dynamic = (config->GetTime_Domain()); - nVar = direct_solver->GetnVar(); + nVar = dynamic? 3*direct_solver->GetnVar() : direct_solver->GetnVar(); nDim = geometry->GetnDim(); /*-- Store some information about direct solver ---*/ @@ -68,7 +67,7 @@ CDiscAdjFEASolver::CDiscAdjFEASolver(CGeometry *geometry, CConfig *config, CSolv /*--- Initialize the adjoint solution. ---*/ vector init(nVar,1e-16); - nodes = new CDiscAdjFEABoundVariable(init.data(), init.data(), init.data(), nPoint, nDim, nVar, dynamic, config); + nodes = new CDiscAdjFEABoundVariable(init.data(), nPoint, nDim, nVar, config); SetBaseClassPointerToNodes(); /*--- Set which points are vertices and allocate boundary data. ---*/ @@ -138,39 +137,16 @@ void CDiscAdjFEASolver::SetRecording(CGeometry* geometry, CConfig *config){ /*--- Reset the solution to the initial (converged) solution ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++){ - direct_solver->GetNodes()->SetSolution(iPoint, nodes->GetSolution_Direct(iPoint)); - } - - if (config->GetTime_Domain()){ - /*--- Reset the solution to the initial (converged) solution ---*/ - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - direct_solver->GetNodes()->SetSolution_Accel(iPoint, nodes->GetSolution_Accel_Direct(iPoint)); - } - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - direct_solver->GetNodes()->SetSolution_Vel(iPoint, nodes->GetSolution_Vel_Direct(iPoint)); - } + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iVar = 0; iVar < nVar; iVar++) + direct_solver->GetNodes()->SetSolution(iPoint, iVar, nodes->GetSolution_Direct(iPoint)[iVar]); - /*--- Reset the input for time n ---*/ + /*--- Reset the input for time n ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ + if (config->GetTime_Domain()) { + for (iPoint = 0; iPoint < nPoint; iPoint++) + for (iVar = 0; iVar < nVar; iVar++) AD::ResetInput(direct_solver->GetNodes()->GetSolution_time_n(iPoint)[iVar]); - } - } - for (iPoint = 0; iPoint < nPoint; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ - AD::ResetInput(direct_solver->GetNodes()->GetSolution_Accel_time_n(iPoint)[iVar]); - } - } - for (iPoint = 0; iPoint < nPoint; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ - AD::ResetInput(direct_solver->GetNodes()->GetSolution_Vel_time_n(iPoint)[iVar]); - } - } - } /*--- Set the Jacobian to zero since this is not done inside the meanflow iteration @@ -188,25 +164,16 @@ void CDiscAdjFEASolver::RegisterSolution(CGeometry *geometry, CConfig *config){ const bool input = true; const bool dynamic = config->GetTime_Domain(); - const bool push_index = !config->GetMultizone_Problem(); /*--- Register solution at all necessary time instances and other variables on the tape ---*/ - direct_solver->GetNodes()->RegisterSolution(input, push_index); + direct_solver->GetNodes()->RegisterSolution(input); if (dynamic) { - /*--- Register acceleration (u'') and velocity (u') at time step n ---*/ - - direct_solver->GetNodes()->RegisterSolution_Accel(input); - direct_solver->GetNodes()->RegisterSolution_Vel(input); - /*--- Register solution (u), acceleration (u'') and velocity (u') at time step n-1 ---*/ - direct_solver->GetNodes()->Register_femSolution_time_n(); - direct_solver->GetNodes()->RegisterSolution_Accel_time_n(); - direct_solver->GetNodes()->RegisterSolution_Vel_time_n(); - + direct_solver->GetNodes()->RegisterSolution_time_n(); } } @@ -240,25 +207,12 @@ void CDiscAdjFEASolver::RegisterVariables(CGeometry *geometry, CConfig *config, } if (!reset) { - const bool local_index = config->GetMultizone_Problem(); - const bool push_index = !local_index; - - E.Register(push_index); - Nu.Register(push_index); - Rho.Register(push_index); - Rho_DL.Register(push_index); - if (de_effects) EField.Register(push_index); - if (fea_dv) DV.Register(push_index); - - /*--- Explicitly store the tape indices for when we extract the derivatives ---*/ - if (local_index) { - E.SetIndex(); - Nu.SetIndex(); - Rho.SetIndex(); - Rho_DL.SetIndex(); - if (de_effects) EField.SetIndex(); - if (fea_dv) DV.SetIndex(); - } + E.Register(); + Nu.Register(); + Rho.Register(); + Rho_DL.Register(); + if (de_effects) EField.Register(); + if (fea_dv) DV.Register(); /*--- Register the flow tractions ---*/ if (config->GetnMarker_Fluid_Load() > 0) @@ -275,162 +229,52 @@ void CDiscAdjFEASolver::RegisterVariables(CGeometry *geometry, CConfig *config, void CDiscAdjFEASolver::RegisterOutput(CGeometry *geometry, CConfig *config){ const bool input = false; - const bool dynamic = config->GetTime_Domain(); - const bool push_index = !config->GetMultizone_Problem(); /*--- Register variables as output of the solver iteration ---*/ - direct_solver->GetNodes()->RegisterSolution(input, push_index); - - if (dynamic) { - /*--- Register acceleration (u'') and velocity (u') at time step n ---*/ - direct_solver->GetNodes()->RegisterSolution_Accel(input); - direct_solver->GetNodes()->RegisterSolution_Vel(input); - } + direct_solver->GetNodes()->RegisterSolution(input); } -void CDiscAdjFEASolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config){ - - const bool dynamic = config->GetTime_Domain(); - const bool multizone = config->GetMultizone_Problem(); - - unsigned short iVar; - unsigned long iPoint; - su2double residual; - - su2double Solution[MAXNVAR] = {0.0}, Solution_Vel[MAXNVAR] = {0.0}, Solution_Accel[MAXNVAR] = {0.0}; - - /*--- Set Residuals to zero ---*/ - - SetResToZero(); +void CDiscAdjFEASolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm) { /*--- Set the old solution, for multi-zone problems this is done after computing the * residuals, otherwise the per-zone-residuals do not make sense, as on entry Solution * contains contributions from other zones but on extraction it does not. ---*/ - if(!multizone) nodes->Set_OldSolution(); - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution ---*/ + if (!config->GetMultizone_Problem()) nodes->Set_OldSolution(); - if(config->GetMultizone_Problem()) { - direct_solver->GetNodes()->GetAdjointSolution_LocalIndex(iPoint,Solution); - } - else { - direct_solver->GetNodes()->GetAdjointSolution(iPoint,Solution); - } - - /*--- Store the adjoint solution ---*/ + /*--- Extract and store the adjoint solution ---*/ + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + su2double Solution[MAXNVAR] = {0.0}; + direct_solver->GetNodes()->GetAdjointSolution(iPoint,Solution); nodes->SetSolution(iPoint,Solution); - } - /*--- Solution for acceleration (u'') and velocity (u') at time n ---*/ - - if (dynamic){ - - /*--- FIRST: The acceleration solution ---*/ - - /*--- Set the old acceleration solution ---*/ - nodes->Set_OldSolution_Accel(); - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint acceleration solution u'' ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_Accel(iPoint,Solution_Accel); - - /*--- Store the adjoint acceleration solution u'' ---*/ - - nodes->SetSolution_Accel(iPoint,Solution_Accel); - - } - - /*--- NEXT: The velocity solution ---*/ - - /*--- Set the old velocity solution ---*/ - nodes->Set_OldSolution_Vel(); - - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint velocity solution u'' ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_Vel(iPoint,Solution_Vel); - - /*--- Store the adjoint velocity solution u'' ---*/ + if (CrossTerm) return; - nodes->SetSolution_Vel(iPoint,Solution_Vel); - - } - - /*--- NOW: The solution at time n ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint solution at time n ---*/ + /*--- Extract and store the adjoint solution at time n (including accel. and velocity) ---*/ + if (config->GetTime_Domain()) { + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { + su2double Solution[MAXNVAR] = {0.0}; direct_solver->GetNodes()->GetAdjointSolution_time_n(iPoint,Solution); - - /*--- Store the adjoint solution at time n ---*/ - nodes->Set_Solution_time_n(iPoint,Solution); } - - /*--- The acceleration solution at time n... ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint acceleration solution u'' at time n ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_Accel_time_n(iPoint,Solution_Accel); - - /*--- Store the adjoint acceleration solution u'' at time n---*/ - - nodes->SetSolution_Accel_time_n(iPoint,Solution_Accel); - - } - - /*--- ... and the velocity solution at time n ---*/ - for (iPoint = 0; iPoint < nPoint; iPoint++){ - - /*--- Extract the adjoint velocity solution u' at time n ---*/ - - direct_solver->GetNodes()->GetAdjointSolution_Vel_time_n(iPoint,Solution_Vel); - - /*--- Store the adjoint velocity solution u' at time n ---*/ - - nodes->SetSolution_Vel_time_n(iPoint,Solution_Vel); - - } - } - /*--- TODO: Need to set the MPI solution in the previous TS ---*/ - /*--- Set the residuals ---*/ - for (iPoint = 0; iPoint < nPointDomain; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ - residual = nodes->GetSolution(iPoint, iVar) - nodes->GetSolution_Old(iPoint, iVar); + SetResToZero(); + + for (auto iPoint = 0ul; iPoint < nPointDomain; iPoint++) { + for (auto iVar = 0u; iVar < nVar; iVar++){ + su2double residual = nodes->GetSolution(iPoint, iVar) - nodes->GetSolution_Old(iPoint, iVar); Residual_RMS[iVar] += residual*residual; AddRes_Max(iVar,fabs(residual),geometry->nodes->GetGlobalIndex(iPoint),geometry->nodes->GetCoord(iPoint)); } - if (dynamic){ - for (iVar = 0; iVar < nVar; iVar++){ - residual = nodes->GetSolution_Accel(iPoint, iVar) - nodes->GetSolution_Old_Accel(iPoint, iVar); - - Residual_RMS[iVar] += residual*residual; - AddRes_Max(iVar,fabs(residual),geometry->nodes->GetGlobalIndex(iPoint),geometry->nodes->GetCoord(iPoint)); - } - for (iVar = 0; iVar < nVar; iVar++){ - residual = nodes->GetSolution_Vel(iPoint, iVar) - nodes->GetSolution_Old_Vel(iPoint, iVar); - - Residual_RMS[iVar] += residual*residual; - AddRes_Max(iVar,fabs(residual),geometry->nodes->GetGlobalIndex(iPoint),geometry->nodes->GetCoord(iPoint)); - } - } } SetResidual_RMS(geometry, config); @@ -468,61 +312,44 @@ void CDiscAdjFEASolver::ExtractAdjoint_Variables(CGeometry *geometry, CConfig *c void CDiscAdjFEASolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config){ - const bool dynamic = (config->GetTime_Domain()); + const bool dynamic = config->GetTime_Domain(); const bool deform_mesh = (config->GetnMarker_Deform_Mesh() > 0); + const bool multizone = config->GetMultizone_Problem(); - su2double Solution[MAXNVAR] = {0.0}, Solution_Vel[MAXNVAR] = {0.0}, Solution_Accel[MAXNVAR] = {0.0}; + su2double Solution[MAXNVAR] = {0.0}; unsigned short iVar; for (auto iPoint = 0ul; iPoint < nPoint; iPoint++){ - for (iVar = 0; iVar < nVar; iVar++){ + for (iVar = 0; iVar < nVar; iVar++) Solution[iVar] = nodes->GetSolution(iPoint,iVar); + + if (dynamic && !multizone) { + for (iVar = 0; iVar < nVar; iVar++) + Solution[iVar] += nodes->GetDual_Time_Derivative(iPoint,iVar); } - if(deform_mesh){ - for (iVar = 0; iVar < nVar; iVar++){ + + if (deform_mesh) { + for (iVar = 0; iVar < nDim; iVar++) Solution[iVar] += nodes->GetSourceTerm_DispAdjoint(iPoint,iVar); + + if (dynamic) { + for (iVar = 0; iVar < nDim; iVar++) + Solution[nDim+iVar] += nodes->GetSourceTerm_VelAdjoint(iPoint,iVar); } } - if (dynamic){ - for (iVar = 0; iVar < nVar; iVar++){ - Solution[iVar] += nodes->GetDynamic_Derivative_n(iPoint,iVar); - } - for (iVar = 0; iVar < nVar; iVar++){ - Solution_Accel[iVar] = nodes->GetSolution_Accel(iPoint,iVar) + nodes->GetDynamic_Derivative_Accel_n(iPoint,iVar); - } - for (iVar = 0; iVar < nVar; iVar++){ - Solution_Vel[iVar] = nodes->GetSolution_Vel(iPoint,iVar) + nodes->GetDynamic_Derivative_Vel_n(iPoint,iVar); - } - } - direct_solver->GetNodes()->SetAdjointSolution(iPoint,Solution); - if (dynamic){ - direct_solver->GetNodes()->SetAdjointSolution_Accel(iPoint,Solution_Accel); - direct_solver->GetNodes()->SetAdjointSolution_Vel(iPoint,Solution_Vel); - } + direct_solver->GetNodes()->SetAdjointSolution(iPoint,Solution); } - } void CDiscAdjFEASolver::Preprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config_container, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output){ - unsigned short iVar; - - if (config_container->GetTime_Domain()){ - for (auto iPoint = 0ul; iPoint < nPoint; iPoint++){ - for (iVar=0; iVar < nVar; iVar++){ - nodes->SetDynamic_Derivative_n(iPoint, iVar, nodes->GetSolution_time_n(iPoint, iVar)); - } - for (iVar=0; iVar < nVar; iVar++){ - nodes->SetDynamic_Derivative_Accel_n(iPoint, iVar, nodes->GetSolution_Accel_time_n(iPoint, iVar)); - } - for (iVar=0; iVar < nVar; iVar++){ - nodes->SetDynamic_Derivative_Vel_n(iPoint, iVar, nodes->GetSolution_Vel_time_n(iPoint, iVar)); - } - } + if (config_container->GetTime_Domain()) { + for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) + for (auto iVar=0u; iVar < nVar; iVar++) + nodes->SetDual_Time_Derivative(iPoint, iVar, nodes->GetSolution_time_n(iPoint, iVar)); } - } void CDiscAdjFEASolver::SetSensitivity(CGeometry *geometry, CConfig *config, CSolver*){ @@ -540,26 +367,25 @@ void CDiscAdjFEASolver::SetSensitivity(CGeometry *geometry, CConfig *config, CSo /*--- Extract the geometric sensitivities ---*/ + const bool time_domain = config->GetTime_Domain(); + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - su2double *Coord = geometry->nodes->GetCoord(iPoint); + auto Coord = geometry->nodes->GetCoord(iPoint); for (unsigned short iDim = 0; iDim < nDim; iDim++) { - su2double Sensitivity; + su2double Sensitivity = geometry->nodes->GetAdjointSolution(iPoint, iDim); + AD::ResetInput(Coord[iDim]); - if(config->GetMultizone_Problem()) { - Sensitivity = geometry->nodes->GetAdjointSolution(iPoint, iDim); + if (!time_domain) { + nodes->SetSensitivity(iPoint, iDim, Sensitivity); + } else { + nodes->SetSensitivity(iPoint, iDim, nodes->GetSensitivity(iPoint, iDim) + Sensitivity); } - else { - Sensitivity = SU2_TYPE::GetDerivative(Coord[iDim]); - /*--- Set the index manually to zero. ---*/ - AD::ResetInput(Coord[iDim]); - } - - nodes->SetSensitivity(iPoint, iDim, Sensitivity); } } + } void CDiscAdjFEASolver::ReadDV(const CConfig *config) { diff --git a/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp b/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp index 90dbc69d2d9..98a93919dc0 100644 --- a/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjMeshSolver.cpp @@ -94,32 +94,30 @@ void CDiscAdjMeshSolver::SetRecording(CGeometry* geometry, CConfig *config){ } END_SU2_OMP_FOR - /*--- Set indices to zero ---*/ - - RegisterVariables(geometry, config, true); - } void CDiscAdjMeshSolver::RegisterSolution(CGeometry *geometry, CConfig *config){ /*--- Register reference mesh coordinates ---*/ - bool input = true; - direct_solver->GetNodes()->Register_MeshCoord(input); + direct_solver->GetNodes()->Register_MeshCoord(); } void CDiscAdjMeshSolver::RegisterVariables(CGeometry *geometry, CConfig *config, bool reset){ + /*--- Register boundary displacements as input. + * Except for FSI, where they are determined by the FEA solver. ---*/ + + if (config->GetFSI_Simulation()) return; + SU2_OMP_MASTER { - /*--- Register boundary displacements as input ---*/ - bool input = true; - direct_solver->GetNodes()->Register_BoundDisp(input); + direct_solver->GetNodes()->Register_BoundDisp(); } END_SU2_OMP_MASTER SU2_OMP_BARRIER } -void CDiscAdjMeshSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config){ +void CDiscAdjMeshSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm){ /*--- Extract the sensitivities of the mesh coordinates ---*/ @@ -142,18 +140,16 @@ void CDiscAdjMeshSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *c void CDiscAdjMeshSolver::ExtractAdjoint_Variables(CGeometry *geometry, CConfig *config){ - /*--- Extract the sensitivities of the boundary displacements ---*/ + /*--- Extract the sensitivities of the boundary displacements, except for FSI. ---*/ + + if (config->GetFSI_Simulation()) return; SU2_OMP_FOR_STAT(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPoint; iPoint++){ - /*--- Extract the adjoint solution of the boundary displacements ---*/ - su2double Solution[MAXNVAR] = {0.0}; direct_solver->GetNodes()->GetAdjoint_BoundDisp(iPoint,Solution); - /*--- Store the sensitivities of the boundary displacements ---*/ - nodes->SetBoundDisp_Sens(iPoint,Solution); } @@ -169,7 +165,7 @@ void CDiscAdjMeshSolver::SetSensitivity(CGeometry *geometry, CConfig *config, CS const auto eps = config->GetAdjSharp_LimiterCoeff()*config->GetRefElemLength(); /*--- Extract the sensitivities ---*/ - ExtractAdjoint_Solution(geometry, config); + ExtractAdjoint_Solution(geometry, config, false); /*--- Extract the adjoint variables: sensitivities of the boundary displacements ---*/ ExtractAdjoint_Variables(geometry, config); diff --git a/SU2_CFD/src/solvers/CDiscAdjSolver.cpp b/SU2_CFD/src/solvers/CDiscAdjSolver.cpp index f0ea580a97e..84ce1b3906c 100644 --- a/SU2_CFD/src/solvers/CDiscAdjSolver.cpp +++ b/SU2_CFD/src/solvers/CDiscAdjSolver.cpp @@ -154,12 +154,11 @@ void CDiscAdjSolver::RegisterSolution(CGeometry *geometry, CConfig *config) { const bool time_n1_needed = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); const bool time_n_needed = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || time_n1_needed; - const bool push_index = !config->GetMultizone_Problem(); /*--- Register solution at all necessary time instances and other variables on the tape ---*/ /*--- Boolean true indicates that an input is registered ---*/ - direct_solver->GetNodes()->RegisterSolution(true, push_index); + direct_solver->GetNodes()->RegisterSolution(true); if (time_n_needed) direct_solver->GetNodes()->RegisterSolution_time_n(); @@ -293,25 +292,19 @@ void CDiscAdjSolver::RegisterVariables(CGeometry *geometry, CConfig *config, boo void CDiscAdjSolver::RegisterOutput(CGeometry *geometry, CConfig *config) { - const bool push_index = !config->GetMultizone_Problem(); - /*--- Register variables as output of the solver iteration. Boolean false indicates that an output is registered ---*/ - direct_solver->GetNodes()->RegisterSolution(false, push_index); + direct_solver->GetNodes()->RegisterSolution(false); } -void CDiscAdjSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config){ +void CDiscAdjSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *config, bool CrossTerm) { const bool time_n1_needed = config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND; const bool time_n_needed = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || time_n1_needed; const su2double relax = (config->GetInnerIter()==0) ? 1.0 : config->GetRelaxation_Factor_Adjoint(); - su2double Solution[MAXNVAR] = {0.0}; - - /*--- Set Residuals to zero ---*/ - - SetResToZero(); + /*--- Thread-local residual variables. ---*/ su2double resMax[MAXNVAR] = {0.0}, resRMS[MAXNVAR] = {0.0}; const su2double* coordMax[MAXNVAR] = {nullptr}; @@ -319,19 +312,15 @@ void CDiscAdjSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *confi /*--- Set the old solution and compute residuals. ---*/ - if(!config->GetMultizone_Problem()) nodes->Set_OldSolution(); + if (!config->GetMultizone_Problem()) nodes->Set_OldSolution(); SU2_OMP_FOR_STAT(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { /*--- Extract the adjoint solution ---*/ - if(config->GetMultizone_Problem()) { - direct_solver->GetNodes()->GetAdjointSolution_LocalIndex(iPoint,Solution); - } - else { - direct_solver->GetNodes()->GetAdjointSolution(iPoint,Solution); - } + su2double Solution[MAXNVAR] = {0.0}; + direct_solver->GetNodes()->GetAdjointSolution(iPoint,Solution); /*--- Relax and store the adjoint solution, compute the residuals. ---*/ @@ -352,6 +341,11 @@ void CDiscAdjSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *confi } END_SU2_OMP_FOR + /*--- Residuals and time_n terms are not needed when evaluating multizone cross terms. ---*/ + if (CrossTerm) return; + + SetResToZero(); + /*--- Reduce residual information over all threads in this rank. ---*/ SU2_OMP_CRITICAL for (auto iVar = 0u; iVar < nVar; iVar++) { @@ -373,10 +367,9 @@ void CDiscAdjSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *confi if (time_n_needed) { SU2_OMP_FOR_STAT(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - + su2double Solution[MAXNVAR] = {0.0}; direct_solver->GetNodes()->GetAdjointSolution_time_n(iPoint,Solution); nodes->Set_Solution_time_n(iPoint,Solution); - } END_SU2_OMP_FOR } @@ -385,10 +378,9 @@ void CDiscAdjSolver::ExtractAdjoint_Solution(CGeometry *geometry, CConfig *confi if (time_n1_needed) { SU2_OMP_FOR_STAT(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { - + su2double Solution[MAXNVAR] = {0.0}; direct_solver->GetNodes()->GetAdjointSolution_time_n1(iPoint,Solution); nodes->Set_Solution_time_n1(iPoint,Solution); - } END_SU2_OMP_FOR } @@ -465,8 +457,10 @@ void CDiscAdjSolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config) { const bool dual_time = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST || config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); + const bool multizone = config->GetMultizone_Problem(); - su2double Solution[MAXNVAR] = {0.0}; /*!< \brief Local container to manipulate the adjoint solution. */ + /*--- Local container to manipulate the adjoint solution. ---*/ + su2double Solution[MAXNVAR] = {0.0}; SU2_OMP_FOR_STAT(omp_chunk_size) for (auto iPoint = 0ul; iPoint < nPoint; iPoint++) { @@ -477,20 +471,16 @@ void CDiscAdjSolver::SetAdjoint_Output(CGeometry *geometry, CConfig *config) { } /*--- Add dual time contributions to the adjoint solution. Two terms stored for DT-2nd-order. ---*/ - if (dual_time) { + if (dual_time && !multizone) { for (auto iVar = 0u; iVar < nVar; iVar++) { Solution[iVar] += nodes->GetDual_Time_Derivative(iPoint,iVar); } } /*--- Set the adjoint values of the primal solution. ---*/ - if(config->GetMultizone_Problem()) { - direct_solver->GetNodes()->SetAdjointSolution_LocalIndex(iPoint,Solution); - } - else { - direct_solver->GetNodes()->SetAdjointSolution(iPoint,Solution); - } - } // for iPoint + + direct_solver->GetNodes()->SetAdjointSolution(iPoint,Solution); + } END_SU2_OMP_FOR } @@ -508,17 +498,7 @@ void CDiscAdjSolver::SetSensitivity(CGeometry *geometry, CConfig *config, CSolve for (auto iDim = 0u; iDim < nDim; iDim++) { - su2double Sensitivity = 0.0; - - if(config->GetMultizone_Problem()) { - Sensitivity = geometry->nodes->GetAdjointSolution(iPoint, iDim); - } - else { - Sensitivity = SU2_TYPE::GetDerivative(Coord[iDim]); - } - - /*--- Set the index manually to zero. ---*/ - + su2double Sensitivity = geometry->nodes->GetAdjointSolution(iPoint, iDim); AD::ResetInput(Coord[iDim]); /*--- If sharp edge, set the sensitivity to 0 on that region ---*/ @@ -526,7 +506,6 @@ void CDiscAdjSolver::SetSensitivity(CGeometry *geometry, CConfig *config, CSolve if (config->GetSens_Remove_Sharp() && geometry->nodes->GetSharpEdge_Distance(iPoint) < eps) { Sensitivity = 0.0; } - if (!time_stepping) { nodes->SetSensitivity(iPoint,iDim, Sensitivity); } else { diff --git a/SU2_CFD/src/solvers/CEulerSolver.cpp b/SU2_CFD/src/solvers/CEulerSolver.cpp index 19ee3038c6f..28a27463418 100644 --- a/SU2_CFD/src/solvers/CEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CEulerSolver.cpp @@ -256,6 +256,8 @@ CEulerSolver::CEulerSolver(CGeometry *geometry, CConfig *config, break; } + SetReferenceValues(*config); + /*--- Initialize fan face pressure, fan face mach number, and mass flow rate ---*/ for (iMarker = 0; iMarker < nMarker; iMarker++) { @@ -1605,6 +1607,29 @@ void CEulerSolver::SetNondimensionalization(CConfig *config, unsigned short iMes } +void CEulerSolver::SetReferenceValues(const CConfig& config) { + + /*--- Evaluate reference values for non-dimensionalization. For dynamic meshes, + use the motion Mach number as a reference value for computing the force coefficients. + Otherwise, use the freestream values, which is the standard convention. ---*/ + + su2double RefVel2; + + if (dynamic_grid && !config.GetFSI_Simulation()) { + su2double Gas_Constant = config.GetGas_ConstantND(); + su2double Mach2Vel = sqrt(Gamma * Gas_Constant * Temperature_Inf); + su2double Mach_Motion = config.GetMach_Motion(); + RefVel2 = pow(Mach_Motion * Mach2Vel, 2); + } + else { + RefVel2 = GeometryToolbox::SquaredNorm(nDim, Velocity_Inf); + } + + DynamicPressureRef = 0.5 * Density_Inf * RefVel2; + AeroCoeffForceRef = DynamicPressureRef * config.GetRefArea(); + +} + void CEulerSolver::SetInitialCondition(CGeometry **geometry, CSolver ***solver_container, CConfig *config, unsigned long TimeIter) { const bool restart = (config->GetRestart() || config->GetRestart_Flow()); @@ -4272,10 +4297,8 @@ void CEulerSolver::ReadActDisk_InputFile(CGeometry *geometry, CSolver **solver_c void CEulerSolver::SetFarfield_AoA(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, bool Output) { - su2double AoA = 0.0, Vel_Infty[3], Vel_Infty_Mag; - unsigned short iDim; - unsigned long InnerIter = config->GetInnerIter(); - su2double Beta = config->GetAoS(); + const auto InnerIter = config->GetInnerIter(); + const su2double AoS = config->GetAoS()*PI_NUMBER/180.0; /* --- Initialize values at first iteration --- */ @@ -4292,7 +4315,7 @@ void CEulerSolver::SetFarfield_AoA(CGeometry *geometry, CSolver **solver_contain /*--- Retrieve the AoA (degrees) ---*/ - AoA = config->GetAoA(); + su2double AoA = config->GetAoA(); /* --- Set new AoA if needed --- */ @@ -4311,63 +4334,38 @@ void CEulerSolver::SetFarfield_AoA(CGeometry *geometry, CSolver **solver_contain /*--- Compute a new value for AoA on the fine mesh only (degrees)---*/ - if (iMesh == MESH_0) AoA = AoA + AoA_inc; - else { AoA = config->GetAoA(); } - - /*--- Only the fine mesh stores the updated values for AoA in config ---*/ - if (iMesh == MESH_0) { + AoA = AoA + AoA_inc; config->SetAoA(AoA); } - /*--- Update the freestream velocity vector at the farfield ---*/ - - for (iDim = 0; iDim < nDim; iDim++) - Vel_Infty[iDim] = GetVelocity_Inf(iDim); - - /*--- Compute the magnitude of the free stream velocity ---*/ + AoA *= PI_NUMBER/180.0; - Vel_Infty_Mag = 0; - for (iDim = 0; iDim < nDim; iDim++) - Vel_Infty_Mag += Vel_Infty[iDim]*Vel_Infty[iDim]; - Vel_Infty_Mag = sqrt(Vel_Infty_Mag); + /*--- Update the freestream velocity vector at the farfield + * Compute the new freestream velocity with the updated AoA, + * "Velocity_Inf" is shared with config. ---*/ - /*--- Compute the new freestream velocity with the updated AoA ---*/ + const su2double Vel_Infty_Mag = GeometryToolbox::Norm(nDim, Velocity_Inf); if (nDim == 2) { - Vel_Infty[0] = cos(AoA*PI_NUMBER/180.0)*Vel_Infty_Mag; - Vel_Infty[1] = sin(AoA*PI_NUMBER/180.0)*Vel_Infty_Mag; - } - if (nDim == 3) { - Vel_Infty[0] = cos(AoA*PI_NUMBER/180.0)*cos(Beta*PI_NUMBER/180.0)*Vel_Infty_Mag; - Vel_Infty[1] = sin(Beta)*Vel_Infty_Mag; - Vel_Infty[2] = sin(AoA*PI_NUMBER/180.0)*cos(Beta*PI_NUMBER/180.0)*Vel_Infty_Mag; + Velocity_Inf[0] = cos(AoA)*Vel_Infty_Mag; + Velocity_Inf[1] = sin(AoA)*Vel_Infty_Mag; } - - /*--- Store the new freestream velocity vector for the next iteration ---*/ - - for (iDim = 0; iDim < nDim; iDim++) { - Velocity_Inf[iDim] = Vel_Infty[iDim]; - } - - /*--- Only the fine mesh stores the updated values for velocity in config ---*/ - - if (iMesh == MESH_0) { - for (iDim = 0; iDim < nDim; iDim++) - config->SetVelocity_FreeStreamND(Vel_Infty[iDim], iDim); + else { + Velocity_Inf[0] = cos(AoA)*cos(AoS)*Vel_Infty_Mag; + Velocity_Inf[1] = sin(AoS)*Vel_Infty_Mag; + Velocity_Inf[2] = sin(AoA)*cos(AoS)*Vel_Infty_Mag; } - } } bool CEulerSolver::FixedCL_Convergence(CConfig* config, bool convergence) { - su2double Target_CL = config->GetTarget_CL(); - unsigned long curr_iter = config->GetInnerIter(); - unsigned long Iter_dCL_dAlpha = config->GetIter_dCL_dAlpha(); + const su2double Target_CL = config->GetTarget_CL(); + const auto curr_iter = config->GetInnerIter(); + const auto Iter_dCL_dAlpha = config->GetIter_dCL_dAlpha(); bool fixed_cl_conv = false; AoA_inc = 0.0; - /*--- if in Fixed CL mode, before finite differencing --- */ if (!Start_AoA_FD){ @@ -4450,7 +4448,6 @@ bool CEulerSolver::FixedCL_Convergence(CConfig* config, bool convergence) { if (convergence && (curr_iter - Iter_Update_AoA) > config->GetStartConv_Iter()) End_AoA_FD = true; - /* --- If Finite Difference mode is ending, reset AoA and calculate Coefficient Gradients --- */ if (End_AoA_FD){ @@ -4464,17 +4461,19 @@ bool CEulerSolver::FixedCL_Convergence(CConfig* config, bool convergence) { } void CEulerSolver::SetCoefficient_Gradients(CConfig *config) const{ - su2double dCL_dAlpha_, dCD_dCL_, dCMx_dCL_, dCMy_dCL_, dCMz_dCL_; - su2double AoA = config->GetAoA(); - if (AoA != AoA_Prev) { - /* --- Calculate gradients of coefficients w.r.t. CL --- */ + const su2double AoA = config->GetAoA(); + + if (AoA == AoA_Prev) return; - dCL_dAlpha_ = (TotalCoeff.CL-Total_CL_Prev)/(AoA - AoA_Prev); - dCD_dCL_ = (TotalCoeff.CD-Total_CD_Prev)/(TotalCoeff.CL-Total_CL_Prev); - dCMx_dCL_ = (TotalCoeff.CMx-Total_CMx_Prev)/(TotalCoeff.CL-Total_CL_Prev); - dCMy_dCL_ = (TotalCoeff.CMy-Total_CMy_Prev)/(TotalCoeff.CL-Total_CL_Prev); - dCMz_dCL_ = (TotalCoeff.CMz-Total_CMz_Prev)/(TotalCoeff.CL-Total_CL_Prev); + /*--- Calculate gradients of coefficients w.r.t. CL ---*/ + + const su2double dCL = TotalCoeff.CL - Total_CL_Prev; + const su2double dCL_dAlpha_ = dCL / (AoA - AoA_Prev); + const su2double dCD_dCL_ = (TotalCoeff.CD-Total_CD_Prev) / dCL; + const su2double dCMx_dCL_ = (TotalCoeff.CMx-Total_CMx_Prev) / dCL; + const su2double dCMy_dCL_ = (TotalCoeff.CMy-Total_CMy_Prev) / dCL; + const su2double dCMz_dCL_ = (TotalCoeff.CMz-Total_CMz_Prev) / dCL; /*--- Set the value of the dOF/dCL in the config file ---*/ @@ -4483,7 +4482,6 @@ void CEulerSolver::SetCoefficient_Gradients(CConfig *config) const{ config->SetdCMy_dCL(dCMy_dCL_); config->SetdCMz_dCL(dCMz_dCL_); config->SetdCL_dAlpha(dCL_dAlpha_); - } } void CEulerSolver::UpdateCustomBoundaryConditions(CGeometry **geometry_container, CConfig *config){ @@ -4793,10 +4791,6 @@ void CEulerSolver::BC_Far_Field(CGeometry *geometry, CSolver **solver_container, visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); - /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ - - visc_numerics->SetTauWall(-1.0, -1.0); - /*--- Compute and update viscous residual ---*/ auto residual = visc_numerics->ComputeResidual(config); @@ -5285,10 +5279,6 @@ void CEulerSolver::BC_Riemann(CGeometry *geometry, CSolver **solver_container, visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); - /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ - - visc_numerics->SetTauWall(-1.0, -1.0); - /*--- Compute and update residual ---*/ auto residual = visc_numerics->ComputeResidual(config); @@ -5803,10 +5793,6 @@ void CEulerSolver::BC_TurboRiemann(CGeometry *geometry, CSolver **solver_contain visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); - /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ - - visc_numerics->SetTauWall(-1.0, -1.0); - /*--- Compute and update residual ---*/ auto residual = visc_numerics->ComputeResidual(config); @@ -6704,10 +6690,6 @@ void CEulerSolver::BC_Giles(CGeometry *geometry, CSolver **solver_container, CNu visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); - /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ - - visc_numerics->SetTauWall(-1.0, -1.0); - /*--- Compute and update residual ---*/ auto residual = visc_numerics->ComputeResidual(config); @@ -7033,10 +7015,6 @@ void CEulerSolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config); @@ -7211,9 +7189,6 @@ void CEulerSolver::BC_Outlet(CGeometry *geometry, CSolver **solver_container, // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config); @@ -7359,10 +7334,6 @@ void CEulerSolver::BC_Supersonic_Inlet(CGeometry *geometry, CSolver **solver_con // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config); @@ -7485,10 +7456,6 @@ void CEulerSolver::BC_Supersonic_Outlet(CGeometry *geometry, CSolver **solver_co // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config); @@ -7709,10 +7676,6 @@ void CEulerSolver::BC_Engine_Inflow(CGeometry *geometry, CSolver **solver_contai // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config); @@ -7964,10 +7927,6 @@ void CEulerSolver::BC_Engine_Exhaust(CGeometry *geometry, CSolver **solver_conta // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config) @@ -8532,10 +8491,6 @@ void CEulerSolver::BC_ActDisk(CGeometry *geometry, CSolver **solver_container, C // visc_numerics->SetTurbKineticEnergy(solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0), // solver_container[TURB_SOL]->GetNodes()->GetSolution(iPoint,0)); // -// /*--- Set the wall shear stress values (wall functions) to -1 (no evaluation using wall functions) ---*/ -// -// visc_numerics->SetTauWall(-1.0, -1.0); -// // /*--- Compute and update residual ---*/ // // auto residual = visc_numerics->ComputeResidual(config); diff --git a/SU2_CFD/src/solvers/CFEASolver.cpp b/SU2_CFD/src/solvers/CFEASolver.cpp index 1e243f73550..7763d01f1b1 100644 --- a/SU2_CFD/src/solvers/CFEASolver.cpp +++ b/SU2_CFD/src/solvers/CFEASolver.cpp @@ -2628,7 +2628,7 @@ void CFEASolver::PredictStruct_Displacement(CGeometry *geometry, const CConfig * } break; } - if (dynamic) nodes->SetSolution_Vel_Pred(iPoint); + if (dynamic) nodes->SetSolution_Vel_Pred(iPoint, nodes->GetSolution_Vel(iPoint)); } END_SU2_OMP_PARALLEL @@ -2744,15 +2744,22 @@ void CFEASolver::SetAitken_Relaxation(CGeometry *geometry, const CConfig *config /*--- Set calculated solution as the old solution (needed for dynamic Aitken relaxation) ---*/ nodes->SetSolution_Old(iPoint, dispCalc); - /*--- Set predicted velocity to update in multizone iterations ---*/ - if (dynamic) nodes->SetSolution_Vel_Pred(iPoint); - /*--- Apply the Aitken relaxation ---*/ su2double newDispPred[MAXNVAR] = {0.0}; for (unsigned short iDim=0; iDim < nDim; iDim++) newDispPred[iDim] = (1.0 - WAitken)*dispPred[iDim] + WAitken*dispCalc[iDim]; nodes->SetSolution_Pred(iPoint, newDispPred); + + /*--- Set predicted velocity to update in multizone iterations ---*/ + if (dynamic) { + su2double newVelPred[MAXNVAR] = {0.0}; + const su2double* velPred = nodes->GetSolution_Vel_Pred(iPoint); + const su2double* velCalc = nodes->GetSolution_Vel(iPoint); + for (unsigned short iDim=0; iDim < nDim; iDim++) + newVelPred[iDim] = (1.0 - WAitken)*velPred[iDim] + WAitken*velCalc[iDim]; + nodes->SetSolution_Vel_Pred(iPoint, newVelPred); + } } END_SU2_OMP_PARALLEL @@ -3189,11 +3196,7 @@ void CFEASolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *c InitiateComms(geometry[MESH_0], config, SOLUTION_FEA); CompleteComms(geometry[MESH_0], config, SOLUTION_FEA); - if (dynamic) { - nodes->Set_Solution_time_n(); - nodes->SetSolution_Vel_time_n(); - nodes->SetSolution_Accel_time_n(); - } + if (dynamic) nodes->Set_Solution_time_n(); if (fluid_structure) { for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint) { @@ -3203,7 +3206,7 @@ void CFEASolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig *c if (dynamic) { for (auto iPoint = 0ul; iPoint < nPoint; ++iPoint) - nodes->SetSolution_Vel_Pred(iPoint); + nodes->SetSolution_Vel_Pred(iPoint, nodes->GetSolution_Vel(iPoint)); } if (discrete_adjoint) { diff --git a/SU2_CFD/src/solvers/CHeatSolver.cpp b/SU2_CFD/src/solvers/CHeatSolver.cpp index c845fa0e8f1..e31233ae6e4 100644 --- a/SU2_CFD/src/solvers/CHeatSolver.cpp +++ b/SU2_CFD/src/solvers/CHeatSolver.cpp @@ -363,8 +363,8 @@ void CHeatSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_containe nVarFlow = solver_container[FLOW_SOL]->GetnVar(); /*--- Define some auxiliary vectors related to the primitive flow solution ---*/ - su2double Primitive_Flow_i[MAXNVAR] = {0}; - su2double Primitive_Flow_j[MAXNVAR] = {0}; + vector Primitive_Flow_i(nVarFlow, 0.0); + vector Primitive_Flow_j(nVarFlow, 0.0); for (auto iEdge = 0ul; iEdge < geometry->GetnEdge(); iEdge++) { @@ -421,7 +421,7 @@ void CHeatSolver::Upwind_Residual(CGeometry *geometry, CSolver **solver_containe Temp_i_Corrected = Temp_i + Project_Temp_i_Grad; Temp_j_Corrected = Temp_j + Project_Temp_j_Grad; - numerics->SetPrimitive(Primitive_Flow_i, Primitive_Flow_j); + numerics->SetPrimitive(Primitive_Flow_i.data(), Primitive_Flow_j.data()); numerics->SetTemperature(Temp_i_Corrected, Temp_j_Corrected); } @@ -571,9 +571,9 @@ void CHeatSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_conta su2double *Normal, *Coord_i, *Coord_j, Area, dist_ij, Twall, dTdn; const bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - const auto laminar_viscosity = config->GetMu_ConstantND(); - const auto Prandtl_Lam = config->GetPrandtl_Lam(); - const auto thermal_diffusivity = flow ? laminar_viscosity/Prandtl_Lam : config->GetThermalDiffusivity_Solid(); + const su2double laminar_viscosity = config->GetMu_ConstantND(); + const su2double Prandtl_Lam = config->GetPrandtl_Lam(); + const su2double thermal_diffusivity = flow ? laminar_viscosity/Prandtl_Lam : config->GetThermalDiffusivity_Solid(); //su2double Prandtl_Turb = config->GetPrandtl_Turb(); //laminar_viscosity = config->GetViscosity_FreeStreamND(); // TDE check for consistency for CHT @@ -832,8 +832,8 @@ void CHeatSolver::BC_ConjugateHeat_Interface(CGeometry *geometry, CSolver **solv const bool implicit = (config->GetKind_TimeIntScheme_Flow() == EULER_IMPLICIT); - const auto Temperature_Ref = config->GetTemperature_Ref(); - const auto rho_cp_solid = config->GetDensity_Solid()*config->GetSpecific_Heat_Cp(); + const su2double Temperature_Ref = config->GetTemperature_Ref(); + const su2double rho_cp_solid = config->GetDensity_Solid()*config->GetSpecific_Heat_Cp(); if (flow) { @@ -1264,9 +1264,6 @@ void CHeatSolver::ExplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_ void CHeatSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_container, CConfig *config) { - unsigned long total_index; - su2double Delta, Vol, *local_Res_TruncError; - /*--- Set maximum residual to zero ---*/ SetResToZero(); @@ -1277,29 +1274,20 @@ void CHeatSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_ /*--- Read the residual ---*/ - local_Res_TruncError = nodes->GetResTruncError(iPoint); - - /*--- Read the volume ---*/ - - Vol = geometry->nodes->GetVolume(iPoint); + su2double* local_Res_TruncError = nodes->GetResTruncError(iPoint); /*--- Modify matrix diagonal to assure diagonal dominance ---*/ if (nodes->GetDelta_Time(iPoint) != 0.0) { - if(flow) { - Delta = Vol / nodes->GetDelta_Time(iPoint); - Jacobian.AddVal2Diag(iPoint, Delta); - } - else if (heat_equation) { - Delta = Vol / nodes->GetDelta_Time(iPoint); - Jacobian.AddVal2Diag(iPoint, Delta); - } + // Identical for flow and heat + const su2double Delta = geometry->nodes->GetVolume(iPoint) / nodes->GetDelta_Time(iPoint); + Jacobian.AddVal2Diag(iPoint, Delta); } else { Jacobian.SetVal2Diag(iPoint, 1.0); for (auto iVar = 0u; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; + const auto total_index = iPoint*nVar + iVar; LinSysRes[total_index] = 0.0; local_Res_TruncError[iVar] = 0.0; } @@ -1308,7 +1296,7 @@ void CHeatSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_ /*--- Right hand side of the system (-Residual) and initial guess (x = 0) ---*/ for (auto iVar = 0; iVar < nVar; iVar++) { - total_index = iPoint*nVar+iVar; + const auto total_index = iPoint*nVar+iVar; LinSysRes[total_index] = - (LinSysRes[total_index] + local_Res_TruncError[iVar]); LinSysSol[total_index] = 0.0; Residual_RMS[iVar] += LinSysRes[total_index]*LinSysRes[total_index]; @@ -1320,7 +1308,7 @@ void CHeatSolver::ImplicitEuler_Iteration(CGeometry *geometry, CSolver **solver_ for (auto iPoint = nPointDomain; iPoint < nPoint; iPoint++) { for (auto iVar = 0u; iVar < nVar; iVar++) { - total_index = iPoint*nVar + iVar; + const auto total_index = iPoint*nVar + iVar; LinSysRes[total_index] = 0.0; LinSysSol[total_index] = 0.0; } diff --git a/SU2_CFD/src/solvers/CIncEulerSolver.cpp b/SU2_CFD/src/solvers/CIncEulerSolver.cpp index 38f0e794d11..3bfad9f5285 100644 --- a/SU2_CFD/src/solvers/CIncEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CIncEulerSolver.cpp @@ -192,6 +192,8 @@ CIncEulerSolver::CIncEulerSolver(CGeometry *geometry, CConfig *config, unsigned break; } + SetReferenceValues(*config); + /*--- Initialize the solution to the far-field state everywhere. ---*/ if (navier_stokes) { @@ -815,6 +817,29 @@ void CIncEulerSolver::SetNondimensionalization(CConfig *config, unsigned short i } +void CIncEulerSolver::SetReferenceValues(const CConfig& config) { + + /*--- Evaluate reference values for non-dimensionalization. For dimensional or non-dim + based on initial values, use the far-field state (inf). For a custom non-dim based + on user-provided reference values, use the ref values to compute the forces. ---*/ + + su2double RefDensity, RefVel2; + + if ((config.GetRef_Inc_NonDim() == DIMENSIONAL) || + (config.GetRef_Inc_NonDim() == INITIAL_VALUES)) { + RefDensity = Density_Inf; + RefVel2 = GeometryToolbox::SquaredNorm(nDim, Velocity_Inf); + } + else { + RefDensity = config.GetInc_Density_Ref(); + RefVel2 = pow(config.GetInc_Velocity_Ref(), 2); + } + + DynamicPressureRef = 0.5 * RefDensity * RefVel2; + AeroCoeffForceRef = DynamicPressureRef * config.GetRefArea(); + +} + void CIncEulerSolver::CommonPreprocessing(CGeometry *geometry, CSolver **solver_container, CConfig *config, unsigned short iMesh, unsigned short iRKStep, unsigned short RunTime_EqSystem, bool Output) { diff --git a/SU2_CFD/src/solvers/CIncNSSolver.cpp b/SU2_CFD/src/solvers/CIncNSSolver.cpp index f1d6d54963e..5a749ddfea8 100644 --- a/SU2_CFD/src/solvers/CIncNSSolver.cpp +++ b/SU2_CFD/src/solvers/CIncNSSolver.cpp @@ -62,6 +62,7 @@ void CIncNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container const bool center = (config->GetKind_ConvNumScheme_Flow() == SPACE_CENTERED); const bool limiter = (config->GetKind_SlopeLimit_Flow() != NO_LIMITER) && (InnerIter <= config->GetLimiterIter()); const bool van_albada = (config->GetKind_SlopeLimit_Flow() == VAN_ALBADA_EDGE); + const bool wall_functions = config->GetWall_Functions(); /*--- Common preprocessing steps (implemented by CEulerSolver) ---*/ @@ -97,6 +98,17 @@ void CIncNSSolver::Preprocessing(CGeometry *geometry, CSolver **solver_container ComputeVorticityAndStrainMag<1>(*config, iMesh); + /*--- Compute the TauWall from the wall functions ---*/ + + if (wall_functions) { + SU2_OMP_MASTER + SetTauWall_WF(geometry, solver_container, config); + END_SU2_OMP_MASTER + // nijso: we have to set this as well?? + // seteddyviscfirstpoint + SU2_OMP_BARRIER + } + /*--- Compute recovered pressure and temperature for streamwise periodic flow ---*/ if (config->GetKind_Streamwise_Periodic() != ENUM_STREAMWISE_PERIODIC::NONE) Compute_Streamwise_Periodic_Recovered_Values(config, geometry, iMesh); @@ -131,9 +143,11 @@ void CIncNSSolver::GetStreamwise_Periodic_Properties(const CGeometry *geometry, for (auto iMarker = 0; iMarker < config->GetnMarker_All(); iMarker++) { - /*--- Only "outlet"/donor periodic marker ---*/ + /*--- Only "outlet"/donor periodic marker. GetnMarker_Periodic counts from 1: First all the inlet marker from + the periodic marker pairs and then the all the outlets. I.e. in order to get the outlet of the first pair + we need to divide the number of periodic markers by 2 and add 1 (because count starts at 1). ---*/ if (config->GetMarker_All_KindBC(iMarker) == PERIODIC_BOUNDARY && - config->GetMarker_All_PerBound(iMarker) == 2) { + config->GetMarker_All_PerBound(iMarker) == (config->GetnMarker_Periodic()/2 + 1)) { for (auto iVertex = 0ul; iVertex < geometry->nVertex[iMarker]; iVertex++) { @@ -145,7 +159,7 @@ void CIncNSSolver::GetStreamwise_Periodic_Properties(const CGeometry *geometry, const auto AreaNormal = geometry->vertex[iMarker][iVertex]->GetNormal(); - auto FaceArea = GeometryToolbox::Norm(nDim, AreaNormal); + const su2double FaceArea = GeometryToolbox::Norm(nDim, AreaNormal); /*--- m_dot = dot_prod(n*v) * A * rho, with n beeing unit normal. ---*/ MassFlow_Local += nodes->GetProjVel(iPoint, AreaNormal) * nodes->GetDensity(iPoint); @@ -154,7 +168,7 @@ void CIncNSSolver::GetStreamwise_Periodic_Properties(const CGeometry *geometry, Average_Density_Local += FaceArea * nodes->GetDensity(iPoint); - /*--- Due to periodicty, temperatures are equal one the inlet(1) and outlet(2) ---*/ + /*--- Due to periodicity, temperatures are equal one the inlet(1) and outlet(2) ---*/ Temperature_Local += FaceArea * nodes->GetTemperature(iPoint); } // if domain @@ -230,7 +244,7 @@ void CIncNSSolver::GetStreamwise_Periodic_Properties(const CGeometry *geometry, /*--- Identify the boundary by string name and retrive heatflux from config ---*/ const auto Marker_StringTag = config->GetMarker_All_TagBound(iMarker); - const auto Wall_HeatFlux = config->GetWall_HeatFlux(Marker_StringTag); + const su2double Wall_HeatFlux = config->GetWall_HeatFlux(Marker_StringTag); for (auto iVertex = 0ul; iVertex < geometry->nVertex[iMarker]; iVertex++) { @@ -240,7 +254,7 @@ void CIncNSSolver::GetStreamwise_Periodic_Properties(const CGeometry *geometry, const auto AreaNormal = geometry->vertex[iMarker][iVertex]->GetNormal(); - auto FaceArea = GeometryToolbox::Norm(nDim, AreaNormal); + const su2double FaceArea = GeometryToolbox::Norm(nDim, AreaNormal); HeatFlow_Local += FaceArea * (-1.0) * Wall_HeatFlux/config->GetHeat_Flux_Ref();; } // loop Vertices @@ -263,7 +277,7 @@ void CIncNSSolver::Compute_Streamwise_Periodic_Recovered_Values(CConfig *config, const auto InnerIter = config->GetInnerIter(); /*--- Reference node on inlet periodic marker to compute relative distance along periodic translation vector. ---*/ - const su2double* ReferenceNode = geometry->GetStreamwise_Periodic_RefNode(); + const auto ReferenceNode = geometry->GetStreamwise_Periodic_RefNode(); /*--- Compute square of the distance between the 2 periodic surfaces. ---*/ const su2double norm2_translation = GeometryToolbox::SquaredNorm(nDim, config->GetPeriodic_Translation(0)); @@ -375,9 +389,11 @@ void CIncNSSolver::BC_Wall_Generic(const CGeometry *geometry, const CConfig *con /*--- Get wall function treatment from config. ---*/ - const auto Wall_Function = config->GetWallFunction_Treatment(Marker_Tag); - if (Wall_Function != NO_WALL_FUNCTION) - SU2_MPI::Error("Wall function treatment not implemented yet", CURRENT_FUNCTION); + //const auto Wall_Function = config->GetWallFunction_Treatment(Marker_Tag); + // nijso: we do not have a special treatment yet for heated walls + // the wall function model is written for heat flux, we have to implement isothermal wall conditions + //if (Wall_Function != WALL_FUNCTIONS::NONE) + // SU2_MPI::Error("Wall function treament not implemented yet", CURRENT_FUNCTION); /*--- Loop over all of the vertices on this boundary marker ---*/ @@ -445,12 +461,12 @@ void CIncNSSolver::BC_Wall_Generic(const CGeometry *geometry, const CConfig *con } else { // ISOTHERMAL - auto Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + const auto Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); /*--- Get coordinates of i & nearest normal and compute distance ---*/ - auto Coord_i = geometry->nodes->GetCoord(iPoint); - auto Coord_j = geometry->nodes->GetCoord(Point_Normal); + const auto Coord_i = geometry->nodes->GetCoord(iPoint); + const auto Coord_j = geometry->nodes->GetCoord(Point_Normal); su2double Edge_Vector[MAXNDIM]; GeometryToolbox::Distance(nDim, Coord_j, Coord_i, Edge_Vector); su2double dist_ij_2 = GeometryToolbox::SquaredNorm(nDim, Edge_Vector); @@ -507,8 +523,7 @@ void CIncNSSolver::BC_ConjugateHeat_Interface(CGeometry *geometry, CSolver **sol /*--- Retrieve the specified wall function treatment.---*/ - const auto Wall_Function = config->GetWallFunction_Treatment(Marker_Tag); - if (Wall_Function != NO_WALL_FUNCTION) { + if (config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::NONE) { SU2_MPI::Error("Wall function treament not implemented yet", CURRENT_FUNCTION); } @@ -555,12 +570,12 @@ void CIncNSSolver::BC_ConjugateHeat_Interface(CGeometry *geometry, CSolver **sol /*--- Compute closest normal neighbor ---*/ - auto Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + const auto Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); /*--- Get coordinates of i & nearest normal and compute distance ---*/ - auto Coord_i = geometry->nodes->GetCoord(iPoint); - auto Coord_j = geometry->nodes->GetCoord(Point_Normal); + const auto Coord_i = geometry->nodes->GetCoord(iPoint); + const auto Coord_j = geometry->nodes->GetCoord(Point_Normal); su2double dist_ij = GeometryToolbox::Distance(nDim, Coord_j, Coord_i); /*--- Compute wall temperature from both temperatures ---*/ @@ -591,3 +606,264 @@ void CIncNSSolver::BC_ConjugateHeat_Interface(CGeometry *geometry, CSolver **sol } END_SU2_OMP_FOR } + +void CIncNSSolver::SetTauWall_WF(CGeometry *geometry, CSolver **solver_container, const CConfig *config) { + /*--- + The wall function implemented herein is based on Nichols and Nelson AIAAJ v32 n6 2004. + At this moment, the wall function is only available for adiabatic flows. + ---*/ + + unsigned long notConvergedCounter = 0; /*--- counts the number of wall cells that are not converged ---*/ + unsigned long smallYPlusCounter = 0; /*--- counts the number of wall cells where y+ < 5 ---*/ + + const su2double Gas_Constant = config->GetGas_ConstantND(); + const su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; + constexpr unsigned short max_iter =200; /*--- maximum number of iterations for the Newton Solver---*/ + const su2double tol = 1e-12; /*--- convergence criterium for the Newton solver, note that 1e-10 is too large ---*/ + const su2double relax = 0.5; /*--- relaxation factor for the Newton solver ---*/ + + /*--- Compute the recovery factor ---*/ + + // Molecular (Laminar) Prandtl number (see Nichols & Nelson, nomenclature ) + const su2double Recovery = pow(config->GetPrandtl_Lam(), (1.0/3.0)); + + /*--- Typical constants from boundary layer theory ---*/ + + const su2double kappa = config->GetwallModelKappa(); + const su2double B = config->GetwallModelB(); + + for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); iMarker++) { + + if (!config->GetViscous_Wall(iMarker)) continue; + + /*--- Identify the boundary by string name ---*/ + + const auto Marker_Tag = config->GetMarker_All_TagBound(iMarker); + + /*--- Jump to another BC if it is not wall function ---*/ + + if (config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::STANDARD_FUNCTION) continue; + + /*--- Get the specified wall heat flux from config ---*/ + // note that we can get the heat flux from the temperature gradient + su2double q_w = 0.0; + + if (config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) + q_w = config->GetWall_HeatFlux(Marker_Tag); + + // heat flux from temperature: q_w = h*(T_wall - T_fluid) + + /*--- Loop over all of the vertices on this boundary marker ---*/ + + SU2_OMP_FOR_DYN(OMP_MIN_SIZE) + for (auto iVertex = 0u; iVertex < geometry->nVertex[iMarker]; iVertex++) { + + const auto iPoint = geometry->vertex[iMarker][iVertex]->GetNode(); + const auto Point_Normal = geometry->vertex[iMarker][iVertex]->GetNormal_Neighbor(); + + /*--- Check if the node belongs to the domain (i.e, not a halo node) + and the neighbor is not part of the physical boundary ---*/ + + if (!geometry->nodes->GetDomain(iPoint)) continue; + + /*--- Get coordinates of the current vertex and nearest normal point ---*/ + + const auto Coord = geometry->nodes->GetCoord(iPoint); + const auto Coord_Normal = geometry->nodes->GetCoord(Point_Normal); + + /*--- Compute dual-grid area and boundary normal ---*/ + + const auto Normal = geometry->vertex[iMarker][iVertex]->GetNormal(); + + su2double Area = GeometryToolbox::Norm(nDim, Normal); + + su2double UnitNormal[MAXNDIM] = {0.0}; + for (auto iDim = 0u; iDim < nDim; iDim++) + UnitNormal[iDim] = -Normal[iDim]/Area; + + /*--- Get the velocity, pressure, and temperature at the nearest + (normal) interior point. ---*/ + + su2double Vel[MAXNDIM] = {0.0}; + for (auto iDim = 0u; iDim < nDim; iDim++) + Vel[iDim] = nodes->GetVelocity(Point_Normal,iDim); + + /*--- Compute the wall-parallel velocity at first point off the wall ---*/ + + su2double VelNormal = GeometryToolbox::DotProduct(int(MAXNDIM), Vel, UnitNormal); + + su2double VelTang[MAXNDIM] = {0.0}; + for (auto iDim = 0u; iDim < nDim; iDim++) + VelTang[iDim] = Vel[iDim] - VelNormal*UnitNormal[iDim]; + + su2double VelTangMod = GeometryToolbox::Norm(int(MAXNDIM), VelTang); + + /*--- Compute normal distance of the interior point from the wall ---*/ + + su2double WallDist[MAXNDIM] = {0.0}; + GeometryToolbox::Distance(nDim, Coord, Coord_Normal, WallDist); + + su2double WallDistMod = GeometryToolbox::Norm(int(MAXNDIM), WallDist); + + /*--- Compute the wall temperature using the Crocco-Buseman equation. + * In incompressible flows, we can assume that there is no velocity-related + * temperature change Prandtl: T+ = Pr*y+ ---*/ + su2double T_Wall = nodes->GetTemperature(iPoint); + + /*--- Extrapolate the pressure from the interior & compute the + wall density using the equation of state ---*/ + + /*--- incompressible formulation ---*/ + su2double Density_Wall = nodes->GetDensity(iPoint); + su2double Conductivity_Wall = nodes->GetThermalConductivity(iPoint); + su2double Lam_Visc_Normal = nodes->GetLaminarViscosity(Point_Normal); + + /*--- Compute the shear stress at the wall in the regular fashion + by using the stress tensor on the surface ---*/ + + su2double tau[MAXNDIM][MAXNDIM] = {{0.0}}; + su2double Lam_Visc_Wall = nodes->GetLaminarViscosity(iPoint); + su2double Eddy_Visc_Wall = nodes->GetEddyViscosity(iPoint); + // do we need the total viscosity for the stress tensor? + //su2double total_viscosity = (Lam_Visc_Wall + Eddy_Visc_Wall); + CNumerics::ComputeStressTensor(nDim, tau, nodes->GetGradient_Primitive(iPoint)+1, Lam_Visc_Wall); + + su2double TauTangent[MAXNDIM] = {0.0}; + GeometryToolbox::TangentProjection(nDim, tau, UnitNormal, TauTangent); + + su2double WallShearStress = GeometryToolbox::Norm(int(MAXNDIM), TauTangent); + + /*--- Calculate the quantities from boundary layer theory and + iteratively solve for a new wall shear stress. Use the current wall + shear stress as a starting guess for the wall function. ---*/ + + unsigned long counter = 0; + su2double diff = 1.0; + su2double U_Tau = max(1.0e-6,sqrt(WallShearStress/Density_Wall)); + su2double Y_Plus = 5.0; // clipping value + + su2double Y_Plus_Start = Density_Wall * U_Tau * WallDistMod / Lam_Visc_Wall; + + /*--- Automatic switch off when y+ < 5 according to Nichols & Nelson (2004) ---*/ + + if (Y_Plus_Start < Y_Plus) { + /*--- impose a minimum y+ for stability reasons---*/ + smallYPlusCounter++; + } + else { + while (fabs(diff) > tol) { + + /*--- Friction velocity and u+ ---*/ + + su2double U_Plus = VelTangMod/U_Tau; + + /*--- Gamma, Beta, Q, and Phi, defined by Nichols & Nelson (2004) page 1110 ---*/ + + su2double Gam = Recovery*U_Tau*U_Tau/(2.0*Cp*T_Wall); + /*--- nijso: heated wall needs validation testcase! ---*/ + su2double Beta = q_w*Lam_Visc_Wall/(Density_Wall*T_Wall*Conductivity_Wall*U_Tau); // TODO: nonzero heatflux needs validation case + su2double Q = sqrt(Beta*Beta + 4.0*Gam); + su2double Phi = asin(-1.0*Beta/Q); + + /*--- Y+ defined by White & Christoph (compressibility and heat transfer) negative value for (2.0*Gam*U_Plus - Beta)/Q ---*/ + + su2double Y_Plus_White = exp((kappa/sqrt(Gam))*(asin((2.0*Gam*U_Plus - Beta)/Q) - Phi))*exp(-1.0*kappa*B); + + /*--- Spalding's universal form for the BL velocity with the + outer velocity form of White & Christoph above. ---*/ + + su2double kUp = kappa*U_Plus; + Y_Plus = U_Plus + Y_Plus_White - (exp(-1.0*kappa*B)* (1.0 + kUp + 0.5*kUp*kUp + kUp*kUp*kUp/6.0)); + + su2double dypw_dyp = 2.0*Y_Plus_White*(kappa*sqrt(Gam)/Q)*sqrt(1.0 - pow(2.0*Gam*U_Plus - Beta,2.0)/(Q*Q)); + + Eddy_Visc_Wall = Lam_Visc_Wall*(1.0 + dypw_dyp - kappa*exp(-1.0*kappa*B)* + (1.0 + kappa*U_Plus + kappa*kappa*U_Plus*U_Plus/2.0) + - Lam_Visc_Normal/Lam_Visc_Wall); + Eddy_Visc_Wall = max(1.0e-6, Eddy_Visc_Wall); + + /* --- Define function for Newton method to zero --- */ + + diff = (Density_Wall * U_Tau * WallDistMod / Lam_Visc_Wall) - Y_Plus; + + /* --- Gradient of function defined above --- */ + + su2double grad_diff = Density_Wall * WallDistMod / Lam_Visc_Wall + VelTangMod / (U_Tau * U_Tau) + + kappa /(U_Tau * sqrt(Gam)) * asin(U_Plus * sqrt(Gam)) * Y_Plus_White - + exp(-1.0 * B * kappa) * (0.5 * pow(VelTangMod * kappa / U_Tau, 3) + + pow(VelTangMod * kappa / U_Tau, 2) + VelTangMod * kappa / U_Tau) / U_Tau; + + /* --- Newton Step --- */ + + U_Tau = U_Tau - relax*(diff / grad_diff); + + counter++; + if (counter > max_iter) { + notConvergedCounter++; + // use some safe values for convergence + Y_Plus = 30.0; + Eddy_Visc_Wall = 1.0; + U_Tau = 1.0; + break; + } + } + } + + /*--- Calculate an updated value for the wall shear stress + using the y+ value, the definition of y+, and the definition of + the friction velocity. ---*/ + + YPlus[iMarker][iVertex] = Y_Plus; + EddyViscWall[iMarker][iVertex] = Eddy_Visc_Wall; + UTau[iMarker][iVertex] = U_Tau; + + // wall model value + su2double Tau_Wall = (1.0/Density_Wall)*pow(Y_Plus*Lam_Visc_Wall/WallDistMod,2.0); + + // nijso: skinfriction for wall functions gives opposite sign? + + for (auto iDim = 0u; iDim < nDim; iDim++) + CSkinFriction[iMarker](iVertex,iDim) = (Tau_Wall/WallShearStress)*TauTangent[iDim] / DynamicPressureRef; + + nodes->SetTauWall(iPoint, Tau_Wall); + // for compressible flow: + //nodes->SetTemperature(iPoint,T_Wall); + //nodes->SetSolution(iPoint, 0, Density_Wall); + //nodes->SetPrimitive(iPoint, nDim + 1, P_Wall); + // for incompressible flow: + // ...? + + } + END_SU2_OMP_FOR + } + + if (config->GetComm_Level() == COMM_FULL) { + static unsigned long globalCounter1, globalCounter2; + + ompMasterAssignBarrier(globalCounter1,0, globalCounter2,0); + + SU2_OMP_ATOMIC + globalCounter1 += notConvergedCounter; + + SU2_OMP_ATOMIC + globalCounter2 += smallYPlusCounter; + + SU2_OMP_BARRIER + SU2_OMP_MASTER { + SU2_MPI::Allreduce(&globalCounter1, ¬ConvergedCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&globalCounter2, &smallYPlusCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + + if (rank == MASTER_NODE) { + if (notConvergedCounter) + cout << "Warning: Computation of wall coefficients (y+) did not converge in " + << notConvergedCounter << " points." << endl; + + if (smallYPlusCounter) + cout << "Warning: y+ < 5.0 in " << smallYPlusCounter + << " points, for which the wall model is not active." << endl; + } + } + END_SU2_OMP_MASTER + } + +} diff --git a/SU2_CFD/src/solvers/CMeshSolver.cpp b/SU2_CFD/src/solvers/CMeshSolver.cpp index ab0446da994..f51bda27186 100644 --- a/SU2_CFD/src/solvers/CMeshSolver.cpp +++ b/SU2_CFD/src/solvers/CMeshSolver.cpp @@ -284,6 +284,7 @@ void CMeshSolver::SetMinMaxVolume(CGeometry *geometry, CConfig *config, bool upd SU2_OMP_BARRIER AD::EndPassive(wasActive); + } void CMeshSolver::SetWallDistance(CGeometry *geometry, CConfig *config) { @@ -502,7 +503,14 @@ void CMeshSolver::DeformMesh(CGeometry **geometry, CNumerics **numerics, CConfig /*--- Clear residual (loses AD info), we do not want an incremental solution. ---*/ SU2_OMP_PARALLEL { LinSysRes.SetValZero(); - if (time_domain && config->GetFSI_Simulation()) LinSysSol.SetValZero(); + + if (time_domain && config->GetFSI_Simulation()) { + SU2_OMP_FOR_STAT(omp_chunk_size) + for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) + for (unsigned short iDim = 0; iDim < nDim; ++iDim) + LinSysSol(iPoint, iDim) = nodes->GetSolution(iPoint, iDim); + END_SU2_OMP_FOR + } } END_SU2_OMP_PARALLEL @@ -519,14 +527,14 @@ void CMeshSolver::DeformMesh(CGeometry **geometry, CNumerics **numerics, CConfig UpdateGridCoord(geometry[MESH_0], config); /*--- Update the dual grid. ---*/ - UpdateDualGrid(geometry[MESH_0], config); + CGeometry::UpdateGeometry(geometry, config); /*--- Check for failed deformation (negative volumes). ---*/ SetMinMaxVolume(geometry[MESH_0], config, true); /*--- The Grid Velocity is only computed if the problem is time domain ---*/ if (time_domain && !config->GetFSI_Simulation()) - ComputeGridVelocity(geometry[MESH_0], config); + ComputeGridVelocity(geometry, config); } END_SU2_OMP_PARALLEL @@ -535,11 +543,6 @@ void CMeshSolver::DeformMesh(CGeometry **geometry, CNumerics **numerics, CConfig ComputeGridVelocity_FromBoundary(geometry, numerics, config); } - /*--- Update the multigrid structure. ---*/ - SU2_OMP_PARALLEL - UpdateMultiGrid(geometry, config); - END_SU2_OMP_PARALLEL - } void CMeshSolver::DeformMesh(CGeometry *geometry, CNumerics **numerics, CConfig *config){ @@ -598,7 +601,7 @@ void CMeshSolver::DeformMesh(CGeometry *geometry, CNumerics **numerics, CConfig } -void CMeshSolver::UpdateGridCoord(CGeometry *geometry, CConfig *config){ +void CMeshSolver::UpdateGridCoord(CGeometry *geometry, const CConfig *config){ /*--- Update the grid coordinates using the solution of the linear system ---*/ @@ -624,17 +627,6 @@ void CMeshSolver::UpdateGridCoord(CGeometry *geometry, CConfig *config){ } -void CMeshSolver::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. ---*/ - - geometry->SetControlVolume(config, UPDATE); - geometry->SetBoundControlVolume(config, UPDATE); - geometry->SetMaxLength(config); - -} - void CMeshSolver::ComputeGridVelocity_FromBoundary(CGeometry **geometry, CNumerics **numerics, CConfig *config){ if (config->GetnZone() == 1) @@ -649,10 +641,18 @@ void CMeshSolver::ComputeGridVelocity_FromBoundary(CGeometry **geometry, CNumeri AD::EndPassive(wasActive); + const su2double velRef = config->GetVelocity_Ref(); + const su2double invVelRef = 1.0 / velRef; + /*--- Clear residual (loses AD info), we do not want an incremental solution. ---*/ SU2_OMP_PARALLEL { LinSysRes.SetValZero(); - LinSysSol.SetValZero(); + + SU2_OMP_FOR_STAT(omp_chunk_size) + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) + for (unsigned short iDim = 0; iDim < nDim; iDim++) + LinSysSol(iPoint, iDim) = geometry[MESH_0]->nodes->GetGridVel(iPoint)[iDim] * velRef; + END_SU2_OMP_FOR } END_SU2_OMP_PARALLEL @@ -662,27 +662,30 @@ void CMeshSolver::ComputeGridVelocity_FromBoundary(CGeometry **geometry, CNumeri /*--- Solve the linear system. ---*/ Solve_System(geometry[MESH_0], config); - SU2_OMP_PARALLEL_(for schedule(static,omp_chunk_size)) - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { - for (unsigned short iDim = 0; iDim < nDim; iDim++) { - su2double val_vel = LinSysSol(iPoint, iDim); - - /*--- Non-dimensionalize velocity ---*/ - val_vel /= config->GetVelocity_Ref(); + SU2_OMP_PARALLEL { + SU2_OMP_FOR_STAT(omp_chunk_size) + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) + for (unsigned short iDim = 0; iDim < nDim; iDim++) + geometry[MESH_0]->nodes->SetGridVel(iPoint, iDim, LinSysSol(iPoint,iDim)*invVelRef); + END_SU2_OMP_FOR - geometry[MESH_0]->nodes->SetGridVel(iPoint, iDim, val_vel); - } + for (auto iMGlevel = 1u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGlevel-1], config); } END_SU2_OMP_PARALLEL + } -void CMeshSolver::ComputeGridVelocity(CGeometry *geometry, CConfig *config){ +void CMeshSolver::ComputeGridVelocity(CGeometry **geometry, const CConfig *config) const { + + /*--- Compute the velocity of each node. ---*/ - /*--- Compute the velocity of each node in the domain of the current rank - (halo nodes are not computed as the grid velocity is later communicated). ---*/ + const bool firstOrder = config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST; + const bool secondOrder = config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND; + const su2double invTimeStep = 1.0 / config->GetDelta_UnstTimeND(); SU2_OMP_FOR_STAT(omp_chunk_size) - for (unsigned long iPoint = 0; iPoint < nPointDomain; iPoint++) { + for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) { /*--- Coordinates of the current point at n+1, n, & n-1 time levels. ---*/ @@ -690,50 +693,23 @@ void CMeshSolver::ComputeGridVelocity(CGeometry *geometry, CConfig *config){ const su2double* Disp_n = nodes->GetSolution_time_n(iPoint); const su2double* Disp_nP1 = nodes->GetSolution(iPoint); - /*--- Unsteady time step ---*/ - - su2double TimeStep = config->GetDelta_UnstTimeND(); - - /*--- Compute mesh velocity with 1st or 2nd-order approximation. ---*/ + /*--- Compute mesh velocity for this point with 1st or 2nd-order approximation. ---*/ for (unsigned short iDim = 0; iDim < nDim; iDim++) { su2double GridVel = 0.0; + if (firstOrder) + GridVel = (Disp_nP1[iDim] - Disp_n[iDim]) * invTimeStep; + else if (secondOrder) + GridVel = (1.5*Disp_nP1[iDim] - 2.0*Disp_n[iDim] + 0.5*Disp_nM1[iDim]) * invTimeStep; - if (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) - GridVel = ( Disp_nP1[iDim] - Disp_n[iDim] ) / TimeStep; - if (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND) - GridVel = ( 3.0*Disp_nP1[iDim] - 4.0*Disp_n[iDim] + - 1.0*Disp_nM1[iDim] ) / (2.0*TimeStep); - - /*--- Store grid velocity for this point ---*/ - - geometry->nodes->SetGridVel(iPoint, iDim, GridVel); - + geometry[MESH_0]->nodes->SetGridVel(iPoint, iDim, GridVel); } } END_SU2_OMP_FOR - /*--- The velocity was computed for nPointDomain, now we communicate it. ---*/ - geometry->InitiateComms(geometry, config, GRID_VELOCITY); - geometry->CompleteComms(geometry, config, GRID_VELOCITY); - -} - -void CMeshSolver::UpdateMultiGrid(CGeometry **geometry, CConfig *config) const{ - - /*--- Update the multigrid structure after moving the finest grid, - including computing the grid velocities on the coarser levels - when the problem is solved in unsteady conditions. ---*/ - - for (auto iMGlevel = 1u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) { - const auto iMGfine = iMGlevel-1; - geometry[iMGlevel]->SetControlVolume(config, geometry[iMGfine], UPDATE); - geometry[iMGlevel]->SetBoundControlVolume(config, geometry[iMGfine],UPDATE); - geometry[iMGlevel]->SetCoord(geometry[iMGfine]); - if (time_domain) - geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGfine], config); - } + for (auto iMGlevel = 1u; iMGlevel <= config->GetnMGLevels(); iMGlevel++) + geometry[iMGlevel]->SetRestricted_GridVelocity(geometry[iMGlevel-1], config); } @@ -886,8 +862,6 @@ void CMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig * minus the coordinates of the reference mesh file ---*/ su2double displ = curr_coord - nodes->GetMesh_Coord(iPoint_Local, iDim); nodes->SetSolution(iPoint_Local, iDim, displ); - su2double vel = Restart_Data[index+iDim+6]; - if (time_domain && config->GetFSI_Simulation()) geometry[MESH_0]->nodes->SetGridVel(iPoint_Local, iDim, vel); } /*--- Increment the overall counter for how many points have been loaded. ---*/ @@ -907,10 +881,6 @@ void CMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig * solver[MESH_0][MESH_SOL]->InitiateComms(geometry[MESH_0], config, SOLUTION); solver[MESH_0][MESH_SOL]->CompleteComms(geometry[MESH_0], config, SOLUTION); - /*--- Communicate the new coordinates at the halos ---*/ - geometry[MESH_0]->InitiateComms(geometry[MESH_0], config, COORDINATES); - geometry[MESH_0]->CompleteComms(geometry[MESH_0], config, COORDINATES); - /*--- Init the linear system solution. ---*/ for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) { for (unsigned short iDim = 0; iDim < nDim; ++iDim) { @@ -918,23 +888,14 @@ void CMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig * } } - /*--- Recompute the edges and dual mesh control volumes in the - domain and on the boundaries. ---*/ - UpdateDualGrid(geometry[MESH_0], config); - - /*--- For time-domain problems, we need to compute the grid velocities ---*/ - if (time_domain){ + /*--- For time-domain problems, we need to compute the grid velocities. ---*/ + if (time_domain && !config->GetFSI_Simulation()) { /*--- Update the old geometry (coordinates n and n-1) ---*/ - Restart_OldGeometry(geometry[MESH_0], config); - /*--- Once Displacement_n and Displacement_n1 are filled, - we can compute the Grid Velocity ---*/ - ComputeGridVelocity(geometry[MESH_0], config); - } + RestartOldGeometry(geometry[MESH_0], config); - /*--- Update the multigrid structure after setting up the finest grid, - including computing the grid velocities on the coarser levels - when the problem is unsteady. ---*/ - UpdateMultiGrid(geometry, config); + /*--- Once Displacement_n and Displacement_n1 are filled we can compute the Grid Velocity ---*/ + ComputeGridVelocity(geometry, config); + } /*--- Store the boundary displacements at the Bound_Disp variable. ---*/ @@ -961,7 +922,7 @@ void CMeshSolver::LoadRestart(CGeometry **geometry, CSolver ***solver, CConfig * } -void CMeshSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { +void CMeshSolver::RestartOldGeometry(CGeometry *geometry, const CConfig *config) { /*--- This function is intended for dual time simulations ---*/ @@ -984,8 +945,10 @@ void CMeshSolver::Restart_OldGeometry(CGeometry *geometry, CConfig *config) { /*--- Modify file name for an unsteady restart ---*/ int Unst_RestartIter; - if (config->GetRestart()) Unst_RestartIter = SU2_TYPE::Int(config->GetRestart_Iter()) - iStep; - else Unst_RestartIter = SU2_TYPE::Int(config->GetUnst_AdjointIter()) - SU2_TYPE::Int(config->GetTimeIter())-iStep-1; + if (!config->GetDiscrete_Adjoint()) + Unst_RestartIter = static_cast(config->GetRestart_Iter()) - iStep; + else + Unst_RestartIter = static_cast(config->GetUnst_AdjointIter()) - config->GetTimeIter() - iStep - 1; if (Unst_RestartIter < 0) { diff --git a/SU2_CFD/src/solvers/CNEMOEulerSolver.cpp b/SU2_CFD/src/solvers/CNEMOEulerSolver.cpp index 27a820d0cc0..e596e225ae0 100644 --- a/SU2_CFD/src/solvers/CNEMOEulerSolver.cpp +++ b/SU2_CFD/src/solvers/CNEMOEulerSolver.cpp @@ -175,6 +175,8 @@ CNEMOEulerSolver::CNEMOEulerSolver(CGeometry *geometry, CConfig *config, break; } + SetReferenceValues(*config); + /*--- Vectorize free stream Mach number based on AoA & AoS ---*/ Mvec_Inf = new su2double[nDim]; Alpha = config->GetAoA()*PI_NUMBER/180.0; @@ -1451,6 +1453,13 @@ void CNEMOEulerSolver::SetNondimensionalization(CConfig *config, unsigned short } } +void CNEMOEulerSolver::SetReferenceValues(const CConfig& config) { + + DynamicPressureRef = 0.5 * Density_Inf * GeometryToolbox::SquaredNorm(nDim, Velocity_Inf); + AeroCoeffForceRef = DynamicPressureRef * config.GetRefArea(); + +} + void CNEMOEulerSolver::BC_Sym_Plane(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { diff --git a/SU2_CFD/src/solvers/CNEMONSSolver.cpp b/SU2_CFD/src/solvers/CNEMONSSolver.cpp index 8c51b809865..3a10d22f102 100644 --- a/SU2_CFD/src/solvers/CNEMONSSolver.cpp +++ b/SU2_CFD/src/solvers/CNEMONSSolver.cpp @@ -969,9 +969,8 @@ void CNEMONSSolver::BC_Smoluchowski_Maxwell(CGeometry *geometry, su2double dTn, dTven; su2double rhoCvtr, rhoCvve; - su2double TauElem[MAXNDIM] = {0.0}, TauTangent[MAXNDIM] = {0.0}; + su2double TauTangent[MAXNDIM] = {0.0}; su2double Tau[MAXNDIM][MAXNDIM] = {{0.0}}; - su2double TauNormal; bool ionization = config->GetIonization(); @@ -1095,14 +1094,8 @@ void CNEMONSSolver::BC_Smoluchowski_Maxwell(CGeometry *geometry, Res_Visc[iVar] = 0.0; CNumerics::ComputeStressTensor(nDim, Tau, Grad_PrimVar+VEL_INDEX, Viscosity); - for (iDim = 0; iDim < nDim; iDim++) - TauElem[iDim] = GeometryToolbox::DotProduct(nDim, Tau[iDim], UnitNormal); - - /*--- Compute wall shear stress (using the stress tensor) ---*/ - TauNormal = GeometryToolbox::DotProduct(nDim, TauElem, UnitNormal); - for (iDim = 0; iDim < nDim; iDim++) - TauTangent[iDim] = TauElem[iDim] - TauNormal * UnitNormal[iDim]; + GeometryToolbox::TangentProjection(nDim, Tau, UnitNormal, TauTangent); /*--- Store the Slip Velocity at the wall */ for (iDim = 0; iDim < nDim; iDim++) diff --git a/SU2_CFD/src/solvers/CNSSolver.cpp b/SU2_CFD/src/solvers/CNSSolver.cpp index 6c602327ff1..f3b57266d66 100644 --- a/SU2_CFD/src/solvers/CNSSolver.cpp +++ b/SU2_CFD/src/solvers/CNSSolver.cpp @@ -417,7 +417,7 @@ void CNSSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_container su2double Wall_HeatFlux = config->GetWall_HeatFlux(Marker_Tag)/config->GetHeat_Flux_Ref(); // Wall_Function = config->GetWallFunction_Treatment(Marker_Tag); -// if (Wall_Function != NO_WALL_FUNCTION) { +// if (Wall_Function != WALL_FUNCTION::NONE) { // SU2_MPI::Error("Wall function treament not implemented yet", CURRENT_FUNCTION); // } @@ -578,7 +578,7 @@ void CNSSolver::BC_Isothermal_Wall_Generic(CGeometry *geometry, CSolver **solver } // Wall_Function = config->GetWallFunction_Treatment(Marker_Tag); -// if (Wall_Function != NO_WALL_FUNCTION) { +// if (Wall_Function != WALL_FUNCTION::NONE) { // SU2_MPI::Error("Wall function treament not implemented yet", CURRENT_FUNCTION); // } @@ -722,33 +722,36 @@ void CNSSolver::BC_Isothermal_Wall_Generic(CGeometry *geometry, CSolver **solver void CNSSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { - BC_Isothermal_Wall_Generic(geometry, solver_container, conv_numerics, visc_numerics, config, val_marker); } void CNSSolver::BC_ConjugateHeat_Interface(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CConfig *config, unsigned short val_marker) { - BC_Isothermal_Wall_Generic(geometry, solver_container, conv_numerics, nullptr, config, val_marker, true); } void CNSSolver::SetTauWall_WF(CGeometry *geometry, CSolver **solver_container, const CConfig *config) { + /*--- + The wall function implemented herein is based on Nichols and Nelson AIAAJ v32 n6 2004. + At this moment, the wall function is only available for adiabatic flows. + ---*/ + unsigned long notConvergedCounter = 0, skipCounter = 0; const su2double Gas_Constant = config->GetGas_ConstantND(); const su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - constexpr unsigned short max_iter = 10; - const su2double tol = 1e-6; - const su2double relax = 0.25; + constexpr unsigned short max_iter = 200; /*--- maximum number of iterations for the Newton Solver---*/ + const su2double tol = 1e-12; /*--- convergence criterium for the Newton solver, note that 1e-10 is too large ---*/ + const su2double relax = 0.5; /*--- relaxation factor for the Newton solver ---*/ /*--- Compute the recovery factor ---*/ - // Double-check: laminar or turbulent Pr for this? + // Molecular (Laminar) Prandtl number (see Nichols & Nelson, nomenclature ) const su2double Recovery = pow(config->GetPrandtl_Lam(), (1.0/3.0)); /*--- Typical constants from boundary layer theory ---*/ - const su2double kappa = 0.4; - const su2double B = 5.5; + const su2double kappa = config->GetwallModelKappa(); + const su2double B = config->GetwallModelB(); for (auto iMarker = 0u; iMarker < config->GetnMarker_All(); iMarker++) { @@ -758,9 +761,18 @@ void CNSSolver::SetTauWall_WF(CGeometry *geometry, CSolver **solver_container, c const auto Marker_Tag = config->GetMarker_All_TagBound(iMarker); + /*--- Jump to another BC if it is not wall function ---*/ + + if (config->GetWallFunction_Treatment(Marker_Tag) != WALL_FUNCTIONS::STANDARD_FUNCTION) + continue; + /*--- Get the specified wall heat flux from config ---*/ + // note that we can get the heat flux from the temperature gradient + su2double q_w = 0.0; + if (config->GetMarker_All_KindBC(iMarker) == HEAT_FLUX) + q_w = config->GetWall_HeatFlux(Marker_Tag); - // Wall_HeatFlux = config->GetWall_HeatFlux(Marker_Tag); + // heat flux from temperature: q_w = h*(T_wall - T_fluid) /*--- Loop over all of the vertices on this boundary marker ---*/ @@ -796,12 +808,13 @@ void CNSSolver::SetTauWall_WF(CGeometry *geometry, CSolver **solver_container, c su2double Vel[MAXNDIM] = {0.0}; for (auto iDim = 0u; iDim < nDim; iDim++) Vel[iDim] = nodes->GetVelocity(Point_Normal,iDim); + su2double P_Normal = nodes->GetPressure(Point_Normal); su2double T_Normal = nodes->GetTemperature(Point_Normal); /*--- Compute the wall-parallel velocity at first point off the wall ---*/ - su2double VelNormal = GeometryToolbox::DotProduct(nDim, Vel, UnitNormal); + su2double VelNormal = GeometryToolbox::DotProduct(int(MAXNDIM), Vel, UnitNormal); su2double VelTang[MAXNDIM] = {0.0}; for (auto iDim = 0u; iDim < nDim; iDim++) @@ -816,67 +829,65 @@ void CNSSolver::SetTauWall_WF(CGeometry *geometry, CSolver **solver_container, c su2double WallDistMod = GeometryToolbox::Norm(int(MAXNDIM), WallDist); - /*--- Compute mach number ---*/ - - // M_Normal = VelTangMod / sqrt(Gamma * Gas_Constant * T_Normal); - /*--- Compute the wall temperature using the Crocco-Buseman equation ---*/ - //T_Wall = T_Normal * (1.0 + 0.5*Gamma_Minus_One*Recovery*M_Normal*M_Normal); + //Mach2_Normal = pow(VelTangMod,2) / (Gamma * Gas_Constant * T_Normal); + //T_Wall = T_Normal * (1.0 + 0.5*Gamma_Minus_One*Recovery*Mach2_Normal); su2double T_Wall = T_Normal + Recovery*pow(VelTangMod,2.0)/(2.0*Cp); /*--- Extrapolate the pressure from the interior & compute the wall density using the equation of state ---*/ + /*--- compressible formulation ---*/ su2double P_Wall = P_Normal; su2double Density_Wall = P_Wall/(Gas_Constant*T_Wall); + su2double Conductivity_Wall = nodes->GetThermalConductivity(iPoint); + su2double Lam_Visc_Normal = nodes->GetLaminarViscosity(Point_Normal); + /*--- Compute the shear stress at the wall in the regular fashion by using the stress tensor on the surface ---*/ - su2double tau[MAXNDIM][MAXNDIM] = {{0.0}}, TauElem[MAXNDIM] = {0.0}; + su2double tau[MAXNDIM][MAXNDIM] = {{0.0}}; su2double Lam_Visc_Wall = nodes->GetLaminarViscosity(iPoint); CNumerics::ComputeStressTensor(nDim, tau, nodes->GetGradient_Primitive(iPoint)+1, Lam_Visc_Wall); - for (auto iDim = 0u; iDim < nDim; iDim++) { - TauElem[iDim] = GeometryToolbox::DotProduct(nDim, tau[iDim], UnitNormal); - } - - /*--- Compute wall shear stress as the magnitude of the wall-tangential - component of the shear stress tensor---*/ - - su2double TauNormal = GeometryToolbox::DotProduct(nDim, TauElem, UnitNormal); - su2double TauTangent[MAXNDIM] = {0.0}; - for (auto iDim = 0u; iDim < nDim; iDim++) - TauTangent[iDim] = TauElem[iDim] - TauNormal * UnitNormal[iDim]; + GeometryToolbox::TangentProjection(nDim, tau, UnitNormal, TauTangent); - su2double Tau_Wall = GeometryToolbox::Norm(int(MAXNDIM), TauTangent); + su2double WallShearStress = GeometryToolbox::Norm(int(MAXNDIM), TauTangent); /*--- Calculate the quantities from boundary layer theory and iteratively solve for a new wall shear stress. Use the current wall shear stress as a starting guess for the wall function. ---*/ - su2double Tau_Wall_Old = Tau_Wall; - unsigned short counter = 0; - su2double diff = 1.0; + unsigned long counter = 0; + su2double diff = 1.0, Eddy_Visc = 1.0; + su2double U_Tau = sqrt(WallShearStress/Density_Wall); + su2double Y_Plus = 5.0; - while (diff > tol) { + su2double Y_Plus_Start = Density_Wall * U_Tau * WallDistMod / Lam_Visc_Wall; + + /*--- Automatic switch off when y+ < 5 according to Nichols & Nelson (2004) ---*/ + + if (Y_Plus_Start < Y_Plus) { + skipCounter++; + } + else while (fabs(diff) > tol) { /*--- Friction velocity and u+ ---*/ - su2double U_Tau = sqrt(Tau_Wall_Old/Density_Wall); su2double U_Plus = VelTangMod/U_Tau; - /*--- Gamma, Beta, Q, and Phi, defined by Nichols & Nelson (2004) ---*/ + /*--- Gamma, Beta, Q, and Phi, defined by Nichols & Nelson (2004) page 1110 ---*/ - su2double Gam = Recovery*pow(U_Tau,2)/(2.0*Cp*T_Wall); - su2double Beta = 0.0; // For adiabatic flows only + su2double Gam = Recovery*U_Tau*U_Tau/(2.0*Cp*T_Wall); + /*--- nijso: heated wall needs validation testcase! ---*/ + su2double Beta = q_w*Lam_Visc_Wall/(Density_Wall*T_Wall*Conductivity_Wall*U_Tau); // TODO: nonzero heatflux needs validation case su2double Q = sqrt(Beta*Beta + 4.0*Gam); su2double Phi = asin(-1.0*Beta/Q); - /*--- Y+ defined by White & Christoph (compressibility and heat transfer) - negative value for (2.0*Gam*U_Plus - Beta)/Q ---*/ + /*--- Y+ defined by White & Christoph (compressibility and heat transfer) negative value for (2.0*Gam*U_Plus - Beta)/Q ---*/ su2double Y_Plus_White = exp((kappa/sqrt(Gam))*(asin((2.0*Gam*U_Plus - Beta)/Q) - Phi))*exp(-1.0*kappa*B); @@ -884,33 +895,92 @@ void CNSSolver::SetTauWall_WF(CGeometry *geometry, CSolver **solver_container, c outer velocity form of White & Christoph above. ---*/ su2double kUp = kappa*U_Plus; - su2double Y_Plus = U_Plus + Y_Plus_White - exp(-1.0*kappa*B) * (1.0 + kUp*(1.0 + 0.5*kUp + pow(kUp,2)/6.0)); + su2double Y_Plus = U_Plus + Y_Plus_White - (exp(-1.0*kappa*B)* (1.0 + kUp + 0.5*kUp*kUp + kUp*kUp*kUp/6.0)); + + su2double dypw_dyp = 2.0*Y_Plus_White*(kappa*sqrt(Gam)/Q)*sqrt(1.0 - pow(2.0*Gam*U_Plus - Beta,2.0)/(Q*Q)); + + Eddy_Visc = Lam_Visc_Wall*(1.0 + dypw_dyp - kappa*exp(-1.0*kappa*B)* + (1.0 + kappa*U_Plus + kappa*kappa*U_Plus*U_Plus/2.0) + - Lam_Visc_Normal/Lam_Visc_Wall); + Eddy_Visc = max(1.0e-6, Eddy_Visc); + + /* --- Define function for Newton method to zero --- */ - /*--- Calculate an updated value for the wall shear stress using the y+ value, - the definition of y+, and the definition of the friction velocity. ---*/ + diff = (Density_Wall * U_Tau * WallDistMod / Lam_Visc_Wall) - Y_Plus; - Tau_Wall = (1.0/Density_Wall)*pow(Y_Plus*Lam_Visc_Wall/WallDistMod,2.0); + /* --- Gradient of function defined above --- */ - /*--- Difference between the old and new Tau. Update old value. ---*/ + su2double grad_diff = Density_Wall * WallDistMod / Lam_Visc_Wall + VelTangMod / (U_Tau * U_Tau) + + kappa /(U_Tau * sqrt(Gam)) * asin(U_Plus * sqrt(Gam)) * Y_Plus_White - + exp(-1.0 * B * kappa) * (0.5 * pow(VelTangMod * kappa / U_Tau, 3) + + pow(VelTangMod * kappa / U_Tau, 2) + VelTangMod * kappa / U_Tau) / U_Tau; - diff = fabs(Tau_Wall-Tau_Wall_Old); - Tau_Wall_Old += relax * (Tau_Wall-Tau_Wall_Old); + /* --- Newton Step --- */ + + U_Tau = U_Tau - relax*(diff / grad_diff); counter++; + if (counter > max_iter) { - cout << "WARNING: Tau_Wall evaluation has not converged in CNSSolver.cpp" << endl; - cout << Tau_Wall_Old << " " << Tau_Wall << " " << diff << endl; + notConvergedCounter++; + // use some safe values for convergence + Y_Plus = 30.0; + Eddy_Visc = 1.0; + U_Tau = 1.0; break; } } + /*--- Calculate an updated value for the wall shear stress + using the y+ value, the definition of y+, and the definition of + the friction velocity. ---*/ + + YPlus[iMarker][iVertex] = Y_Plus; + EddyViscWall[iMarker][iVertex] = Eddy_Visc; + UTau[iMarker][iVertex] = U_Tau; + + // wall model value + su2double Tau_Wall = (1.0/Density_Wall)*pow(Y_Plus*Lam_Visc_Wall/WallDistMod,2.0); + + for (auto iDim = 0u; iDim < nDim; iDim++) + CSkinFriction[iMarker](iVertex,iDim) = (Tau_Wall/WallShearStress)*TauTangent[iDim] / DynamicPressureRef; + /*--- Store this value for the wall shear stress at the node. ---*/ nodes->SetTauWall(iPoint, Tau_Wall); } - END_SU2_OMP_FOR } + END_SU2_OMP_FOR + + if (config->GetComm_Level() == COMM_FULL) { + static unsigned long globalCounter1, globalCounter2; + + ompMasterAssignBarrier(globalCounter1,0, globalCounter2,0); + + SU2_OMP_ATOMIC + globalCounter1 += notConvergedCounter; + + SU2_OMP_ATOMIC + globalCounter2 += skipCounter; + + SU2_OMP_BARRIER + SU2_OMP_MASTER { + SU2_MPI::Allreduce(&globalCounter1, ¬ConvergedCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + SU2_MPI::Allreduce(&globalCounter2, &skipCounter, 1, MPI_UNSIGNED_LONG, MPI_SUM, SU2_MPI::GetComm()); + + if (rank == MASTER_NODE) { + if (notConvergedCounter) + cout << "Warning: Computation of wall coefficients (y+) did not converge in " + << notConvergedCounter << " points." << endl; + + if (skipCounter) + cout << "Warning: y+ < 5.0 in " << skipCounter + << " points, for which the wall model is not active." << endl; + } + } + END_SU2_OMP_MASTER + } } diff --git a/SU2_CFD/src/solvers/CSolver.cpp b/SU2_CFD/src/solvers/CSolver.cpp index c36e6404f54..9f8da0fbd13 100644 --- a/SU2_CFD/src/solvers/CSolver.cpp +++ b/SU2_CFD/src/solvers/CSolver.cpp @@ -3129,7 +3129,7 @@ void CSolver::InterpolateRestartData(const CGeometry *geometry, const CConfig *c if (size != SINGLE_NODE && size % 2) SU2_MPI::Error("Number of ranks must be multiple of 2.", CURRENT_FUNCTION); - if (config->GetStructuralProblem() || config->GetFEMSolver()) + if (config->GetFEMSolver()) SU2_MPI::Error("Cannot interpolate the restart file for FEM problems.", CURRENT_FUNCTION); /* Challenges: diff --git a/SU2_CFD/src/solvers/CTurbSASolver.cpp b/SU2_CFD/src/solvers/CTurbSASolver.cpp index 67e875c2422..21d307bdac0 100644 --- a/SU2_CFD/src/solvers/CTurbSASolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSASolver.cpp @@ -413,7 +413,7 @@ void CTurbSASolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_conta if (config->GetWall_Functions()) { SU2_OMP_MASTER - SetNuTilde_WF(geometry, solver_container, conv_numerics, visc_numerics, config, val_marker); + SetTurbVars_WF(geometry, solver_container, config, val_marker); END_SU2_OMP_MASTER SU2_OMP_BARRIER return; @@ -580,7 +580,6 @@ void CTurbSASolver::BC_Inlet(CGeometry *geometry, CSolver **solver_container, CN conv_numerics->SetPrimitive(V_domain, V_inlet); - /*--- Set the turbulent variable states (prescribed for an inflow) ---*/ /*--- Load the inlet turbulence variable (uniform by default). ---*/ conv_numerics->SetTurbVar(nodes->GetSolution(iPoint), Inlet_TurbVars[val_marker][iVertex]); @@ -1574,24 +1573,20 @@ void CTurbSASolver::BC_NearField_Boundary(CGeometry *geometry, CSolver **solver_ // } -void CTurbSASolver::SetNuTilde_WF(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, - CNumerics *visc_numerics, const CConfig *config, unsigned short val_marker) { +void CTurbSASolver::SetTurbVars_WF(CGeometry *geometry, CSolver **solver_container, + const CConfig *config, unsigned short val_marker) { const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); - const su2double Gas_Constant = config->GetGas_ConstantND(); - const su2double Cp = (Gamma / Gamma_Minus_One) * Gas_Constant; - constexpr unsigned short max_iter = 100; - const su2double tol = 1e-10; + /*--- We use a very high max nr of iterations, but we only need this the first couple of iterations ---*/ + constexpr unsigned short max_iter = 200; - /*--- Compute the recovery factor ---*/ - // su2double-check: laminar or turbulent Pr for this? - const su2double Recovery = pow(config->GetPrandtl_Lam(),(1.0/3.0)); + /* --- tolerance has LARGE impact on convergence, do not increase this value! --- */ + const su2double tol = 1e-12; + su2double relax = 0.5; /*--- relaxation factor for the Newton solver ---*/ /*--- Typical constants from boundary layer theory ---*/ - const su2double kappa = 0.4; - const su2double B = 5.5; const su2double cv1_3 = 7.1*7.1*7.1; CVariable* flow_nodes = solver_container[FLOW_SOL]->GetNodes(); @@ -1600,126 +1595,63 @@ void CTurbSASolver::SetNuTilde_WF(CGeometry *geometry, CSolver **solver_containe for (auto iVertex = 0u; iVertex < geometry->nVertex[val_marker]; iVertex++) { - const auto Point_Normal = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - - if (!geometry->nodes->GetDomain(Point_Normal)) continue; - const auto iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + const auto iPoint_Neighbor = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); - /*--- Compute dual-grid area and boundary normal ---*/ - - const auto Normal = geometry->vertex[val_marker][iVertex]->GetNormal(); - - su2double Area = GeometryToolbox::Norm(nDim, Normal); - - su2double UnitNormal[MAXNDIM] = {0.0}; - for (auto iDim = 0u; iDim < nDim; iDim++) - UnitNormal[iDim] = -Normal[iDim]/Area; - - /*--- Get the velocity, pressure, and temperature at the nearest - (normal) interior point. ---*/ - - su2double Vel[MAXNDIM] = {0.0}; - for (auto iDim = 0u; iDim < nDim; iDim++) - Vel[iDim] = flow_nodes->GetVelocity(Point_Normal,iDim); - su2double P_Normal = flow_nodes->GetPressure(Point_Normal); - su2double T_Normal = flow_nodes->GetTemperature(Point_Normal); - - /*--- Compute the wall-parallel velocity at first point off the wall ---*/ - - su2double VelNormal = GeometryToolbox::DotProduct(int(MAXNDIM), Vel, UnitNormal); - - su2double VelTang[MAXNDIM] = {0.0}; - for (auto iDim = 0u; iDim < nDim; iDim++) - VelTang[iDim] = Vel[iDim] - VelNormal*UnitNormal[iDim]; - - su2double VelTangMod = GeometryToolbox::Norm(int(MAXNDIM), VelTang); - - /*--- Compute the wall temperature using the Crocco-Buseman equation ---*/ - - //T_Wall = T_Normal * (1.0 + 0.5*Gamma_Minus_One*Recovery*M_Normal*M_Normal); - su2double T_Wall = T_Normal + Recovery*pow(VelTangMod,2.0)/(2.0*Cp); - - /*--- Extrapolate the pressure from the interior & compute the - wall density using the equation of state ---*/ - - su2double P_Wall = P_Normal; - su2double Density_Wall = P_Wall/(Gas_Constant*T_Wall); - - /*--- Get wall shear stress computed by flow solver ---*/ - - su2double Lam_Visc_Wall = flow_nodes->GetLaminarViscosity(iPoint); - su2double Tau_Wall = flow_nodes->GetTauWall(iPoint); - - /*--- Friction velocity and u+ ---*/ - - su2double U_Tau = sqrt(Tau_Wall/Density_Wall); - su2double U_Plus = VelTangMod/U_Tau; - - /*--- Gamma, Beta, Q, and Phi, defined by Nichols & Nelson (2004) ---*/ - - su2double Gam = Recovery*U_Tau*U_Tau/(2.0*Cp*T_Wall); - su2double Beta = 0.0; // For adiabatic flows only - su2double Q = sqrt(Beta*Beta + 4.0*Gam); - su2double Phi = asin(-1.0*Beta/Q); - - /*--- Y+ defined by White & Christoph (compressibility and heat transfer) - negative value for (2.0*Gam*U_Plus - Beta)/Q ---*/ - - su2double Y_Plus_White = exp((kappa/sqrt(Gam))*(asin((2.0*Gam*U_Plus - Beta)/Q) - Phi))*exp(-1.0*kappa*B); - - /*--- Now compute the Eddy viscosity at the first point off of the wall ---*/ + /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ - su2double Lam_Visc_Normal = flow_nodes->GetLaminarViscosity(Point_Normal); - su2double Density_Normal = flow_nodes->GetDensity(Point_Normal); - su2double Kin_Visc_Normal = Lam_Visc_Normal/Density_Normal; + if (geometry->nodes->GetDomain(iPoint_Neighbor)) { - su2double dypw_dyp = 2.0*Y_Plus_White*(kappa*sqrt(Gam)/Q)*sqrt(1.0 - pow(2.0*Gam*U_Plus - Beta,2.0)/(Q*Q)); - su2double Eddy_Visc = Lam_Visc_Wall*(1.0 + dypw_dyp - kappa*exp(-1.0*kappa*B)* - (1.0 + kappa*U_Plus + kappa*kappa*U_Plus*U_Plus/2.0) - - Lam_Visc_Normal/Lam_Visc_Wall); + su2double Y_Plus = solver_container[FLOW_SOL]->GetYPlus(val_marker, iVertex); - /*--- Eddy viscosity should be always a positive number ---*/ + /*--- note that we do not do anything for y+ < 5, meaning that we have a zero flux (Neumann) boundary condition ---*/ - Eddy_Visc = max(0.0, Eddy_Visc); + if (Y_Plus < 5.0) continue; - /*--- Solve for the new value of nu_tilde given the eddy viscosity and using a Newton method ---*/ + su2double Lam_Visc_Normal = flow_nodes->GetLaminarViscosity(iPoint_Neighbor); + su2double Density_Normal = flow_nodes->GetDensity(iPoint_Neighbor); + su2double Kin_Visc_Normal = Lam_Visc_Normal/Density_Normal; - su2double nu_til_old = nodes->GetSolution(iPoint,0); + su2double Eddy_Visc = solver_container[FLOW_SOL]->GetEddyViscWall(val_marker, iVertex); - unsigned short counter = 0; - su2double diff = 1.0; + /*--- Solve for the new value of nu_tilde given the eddy viscosity and using a Newton method ---*/ - while (diff > tol) { + // start with positive value of nu_til_old + su2double nu_til = 0.0; + su2double nu_til_old = nodes->GetSolution(iPoint,0); - su2double const_term = (Eddy_Visc/Density_Normal) * pow(Kin_Visc_Normal,3)*cv1_3; + unsigned short counter = 0; + su2double diff = 1.0; + relax = 0.5; + while (diff > tol) { + // note the error in Nichols and Nelson + su2double func = pow(nu_til_old,4) - (Eddy_Visc/Density_Normal)*(pow(nu_til_old,3) + pow(Kin_Visc_Normal,3)*cv1_3); + su2double func_prim = 4.0 * pow(nu_til_old,3) - 3.0*(Eddy_Visc/Density_Normal)*pow(nu_til_old,2); - su2double nu_til_2 = pow(nu_til_old,2); - su2double nu_til_3 = nu_til_old * nu_til_2; + // damped Newton method + nu_til = nu_til_old - relax*(func/func_prim); - su2double func = nu_til_old * (nu_til_3 - (Eddy_Visc/Density_Normal)*nu_til_2) + const_term; - su2double func_prime = 4.0*nu_til_3 - 3.0*(Eddy_Visc/Density_Normal)*nu_til_2; - su2double nu_til = nu_til_old - func/func_prime; + diff = fabs(nu_til-nu_til_old); + nu_til_old = nu_til; - diff = fabs(nu_til-nu_til_old); - nu_til_old = nu_til; + // sometimes we get negative values when the solution has not converged yet, we just reset the nu_tilde in that case. + if (nu_til_oldGetSolution(iPoint,0)/relax; + } - counter++; - if (counter > max_iter) { - cout << "WARNING: Nu_tilde evaluation has not converged." << endl; - break; + counter++; + if (counter > max_iter) break; } - } - - nodes->SetSolution_Old(Point_Normal, 0, nu_til_old); - LinSysRes.SetBlock_Zero(Point_Normal); - /*--- includes 1 in the diagonal ---*/ + nodes->SetSolution_Old(iPoint_Neighbor, &nu_til); + LinSysRes.SetBlock_Zero(iPoint_Neighbor); - if (implicit) Jacobian.DeleteValsRowi(Point_Normal); + /*--- includes 1 in the diagonal ---*/ + if (implicit) Jacobian.DeleteValsRowi(iPoint_Neighbor); + } } - } void CTurbSASolver::SetDES_LengthScale(CSolver **solver, CGeometry *geometry, CConfig *config){ diff --git a/SU2_CFD/src/solvers/CTurbSSTSolver.cpp b/SU2_CFD/src/solvers/CTurbSSTSolver.cpp index 6c06747d7fa..819a57c0a49 100644 --- a/SU2_CFD/src/solvers/CTurbSSTSolver.cpp +++ b/SU2_CFD/src/solvers/CTurbSSTSolver.cpp @@ -367,16 +367,24 @@ void CTurbSSTSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_cont tie(WallType, Roughness_Height) = config->GetWallRoughnessProperties(Marker_Tag); if (WallType == WALL_TYPE::ROUGH) rough_wall = true; + /*--- Evaluate nu tilde at the closest point to the surface using the wall functions. ---*/ + + if (config->GetWall_Functions()) { + SU2_OMP_MASTER + SetTurbVars_WF(geometry, solver_container, config, val_marker); + END_SU2_OMP_MASTER + SU2_OMP_BARRIER + return; + } + SU2_OMP_FOR_STAT(OMP_MIN_SIZE) for (auto iVertex = 0u; iVertex < geometry->nVertex[val_marker]; iVertex++) { - const auto iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); /*--- Check if the node belongs to the domain (i.e, not a halo node) ---*/ if (geometry->nodes->GetDomain(iPoint)) { - if (rough_wall) { /*--- Set wall values ---*/ @@ -413,7 +421,9 @@ void CTurbSSTSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_cont nodes->SetSolution_Old(iPoint,solution); nodes->SetSolution(iPoint,solution); LinSysRes.SetBlock_Zero(iPoint); - } else { + + } else { // smooth wall + /*--- distance to closest neighbor ---*/ const auto jPoint = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); @@ -426,7 +436,7 @@ void CTurbSSTSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_cont su2double laminar_viscosity = solver_container[FLOW_SOL]->GetNodes()->GetLaminarViscosity(jPoint); su2double beta_1 = constants[4]; - su2double solution[2]; + su2double solution[MAXNVAR]; solution[0] = 0.0; solution[1] = 60.0*laminar_viscosity/(density*beta_1*distance2); @@ -446,6 +456,64 @@ void CTurbSSTSolver::BC_HeatFlux_Wall(CGeometry *geometry, CSolver **solver_cont END_SU2_OMP_FOR } + +void CTurbSSTSolver::SetTurbVars_WF(CGeometry *geometry, CSolver **solver_container, + const CConfig *config, unsigned short val_marker) { + + const bool implicit = (config->GetKind_TimeIntScheme() == EULER_IMPLICIT); + + /*--- von Karman constant from boundary layer theory ---*/ + const su2double kappa = config->GetwallModelKappa(); + + /*--- relaxation factor for k-omega values ---*/ + const su2double relax = 0.5; + + /*--- Loop over all of the vertices on this boundary marker ---*/ + + for (auto iVertex = 0u; iVertex < geometry->nVertex[val_marker]; iVertex++) { + + const auto iPoint = geometry->vertex[val_marker][iVertex]->GetNode(); + const auto iPoint_Neighbor = geometry->vertex[val_marker][iVertex]->GetNormal_Neighbor(); + + su2double Y_Plus = solver_container[FLOW_SOL]->GetYPlus(val_marker, iVertex); + su2double Lam_Visc_Wall = solver_container[FLOW_SOL]->GetNodes()->GetLaminarViscosity(iPoint); + + /*--- Do not use wall model at the ipoint when y+ < 5.0, use zero flux (Neumann) conditions. ---*/ + + if (Y_Plus < 5.0) continue; + + su2double Eddy_Visc = solver_container[FLOW_SOL]->GetEddyViscWall(val_marker, iVertex); + su2double k = nodes->GetSolution(iPoint_Neighbor,0); + su2double omega = nodes->GetSolution(iPoint_Neighbor,1); + su2double Density_Wall = solver_container[FLOW_SOL]->GetNodes()->GetDensity(iPoint); + su2double U_Tau = solver_container[FLOW_SOL]->GetUTau(val_marker, iVertex); + su2double y = Y_Plus*Lam_Visc_Wall/(Density_Wall*U_Tau); + + su2double omega1 = 6.0*Lam_Visc_Wall/(0.075*Density_Wall*y*y); // eq. 19 + su2double omega0 = U_Tau/(sqrt(0.09)*kappa*y); // eq. 20 + su2double omega_new = sqrt(omega0*omega0 + omega1*omega1); // eq. 21 Nichols & Nelson + su2double k_new = omega_new * Eddy_Visc/Density_Wall; // eq. 22 Nichols & Nelson + // (is this the correct density? paper says rho and not rho_w) + + /*--- put some relaxation factor on the k-omega values ---*/ + k += relax*(k_new - k); + omega += relax*(omega_new - omega); + + su2double solution[MAXNVAR] = {k, omega}; + + nodes->SetSolution_Old(iPoint_Neighbor,solution); + nodes->SetSolution(iPoint,solution); + + LinSysRes.SetBlock_Zero(iPoint_Neighbor); + + if (implicit) { + /*--- includes 1 in the diagonal ---*/ + Jacobian.DeleteValsRowi(iPoint_Neighbor*nVar); + Jacobian.DeleteValsRowi(iPoint_Neighbor*nVar+1); + } + } +} + void CTurbSSTSolver::BC_Isothermal_Wall(CGeometry *geometry, CSolver **solver_container, CNumerics *conv_numerics, CNumerics *visc_numerics, CConfig *config, unsigned short val_marker) { diff --git a/SU2_CFD/src/variables/CDiscAdjFEABoundVariable.cpp b/SU2_CFD/src/variables/CDiscAdjFEABoundVariable.cpp index 4c2c3bf5733..09234c1c67e 100644 --- a/SU2_CFD/src/variables/CDiscAdjFEABoundVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjFEABoundVariable.cpp @@ -25,12 +25,11 @@ * License along with SU2. If not, see . */ - #include "../../include/variables/CDiscAdjFEABoundVariable.hpp" -CDiscAdjFEABoundVariable::CDiscAdjFEABoundVariable(const su2double *disp, const su2double *vel, - const su2double *accel, unsigned long npoint, unsigned long ndim, unsigned long nvar, bool unsteady, CConfig *config) : - CDiscAdjFEAVariable(disp, vel, accel, npoint, ndim, nvar, unsteady, config) { +CDiscAdjFEABoundVariable::CDiscAdjFEABoundVariable(const su2double *sol, unsigned long npoint, unsigned long ndim, + unsigned long nvar, CConfig *config) : + CDiscAdjVariable(sol, npoint, ndim, nvar, config) { VertexMap.Reset(nPoint); } @@ -47,5 +46,6 @@ void CDiscAdjFEABoundVariable::AllocateBoundaryVariables(CConfig *config) { FlowTraction_Sens.resize(nBoundPt,nDim) = su2double(0.0); SourceTerm_DispAdjoint.resize(nBoundPt,nDim) = su2double(0.0); + SourceTerm_VelAdjoint.resize(nBoundPt,nDim) = su2double(0.0); } diff --git a/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp b/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp deleted file mode 100644 index b1cdc07c433..00000000000 --- a/SU2_CFD/src/variables/CDiscAdjFEAVariable.cpp +++ /dev/null @@ -1,81 +0,0 @@ -/*! - * \file CDiscAdjFEAVariable.cpp - * \brief Definition of the variables for FEM adjoint elastic structural problems. - * \author R. Sanchez - * \version 7.1.1 "Blackbird" - * - * SU2 Project Website: https://su2code.github.io - * - * The SU2 Project is maintained by the SU2 Foundation - * (http://su2foundation.org) - * - * Copyright 2012-2021, 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/variables/CDiscAdjFEAVariable.hpp" - - -CDiscAdjFEAVariable::CDiscAdjFEAVariable(const su2double *disp, const su2double *vel, const su2double *accel, unsigned long npoint, - unsigned long ndim, unsigned long nvar, bool unsteady, CConfig *config) : CVariable(npoint, ndim, nvar, config) { - - Solution_Direct.resize(nPoint,nVar); - - Sensitivity.resize(nPoint,nDim) = su2double(0.0); - - for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - Solution(iPoint,iVar) = disp[iVar]; - - if (config->GetMultizone_Problem() && config->GetDiscrete_Adjoint()) { - External.resize(nPoint,nVar) = su2double(0.0); - } - - /*--- Nothing else to allocate ---*/ - if (!unsteady) return; - - - Dynamic_Derivative.resize(nPoint,nVar) = su2double(0.0); - Dynamic_Derivative_n.resize(nPoint,nVar) = su2double(0.0); - Dynamic_Derivative_Vel.resize(nPoint,nVar) = su2double(0.0); - Dynamic_Derivative_Vel_n.resize(nPoint,nVar) = su2double(0.0); - Dynamic_Derivative_Accel.resize(nPoint,nVar) = su2double(0.0); - Dynamic_Derivative_Accel_n.resize(nPoint,nVar) = su2double(0.0); - - Solution_Direct_Vel.resize(nPoint,nVar) = su2double(0.0); - Solution_Direct_Accel.resize(nPoint,nVar) = su2double(0.0); - - Solution_Vel.resize(nPoint,nVar); - Solution_Accel.resize(nPoint,nVar); - - Solution_Old_Vel.resize(nPoint,nVar) = su2double(0.0); - Solution_Old_Accel.resize(nPoint,nVar) = su2double(0.0); - - Solution_Vel_time_n.resize(nPoint,nVar) = su2double(0.0); - Solution_Accel_time_n.resize(nPoint,nVar) = su2double(0.0); - - for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) { - for (unsigned long iVar = 0; iVar < nVar; iVar++) { - Solution_Vel(iPoint,iVar) = vel[iVar]; - Solution_Accel(iPoint,iVar) = accel[iVar]; - } - } - -} - -void CDiscAdjFEAVariable::Set_OldSolution_Vel() { Solution_Old_Vel = Solution_Vel; } - -void CDiscAdjFEAVariable::Set_OldSolution_Accel() { Solution_Old_Accel = Solution_Accel; } diff --git a/SU2_CFD/src/variables/CDiscAdjVariable.cpp b/SU2_CFD/src/variables/CDiscAdjVariable.cpp index ae1133ad6a4..d6e697f3005 100644 --- a/SU2_CFD/src/variables/CDiscAdjVariable.cpp +++ b/SU2_CFD/src/variables/CDiscAdjVariable.cpp @@ -25,25 +25,17 @@ * License along with SU2. If not, see . */ - #include "../../include/variables/CDiscAdjVariable.hpp" +CDiscAdjVariable::CDiscAdjVariable(const su2double* sol, unsigned long npoint, unsigned long ndim, + unsigned long nvar, CConfig *config) : + CVariable(npoint, ndim, nvar, config, true) { -CDiscAdjVariable::CDiscAdjVariable(const su2double* sol, unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config) - : CVariable(npoint, ndim, nvar, config) { - - bool dual_time = (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_1ST) || - (config->GetTime_Marching() == TIME_MARCHING::DT_STEPPING_2ND); - - bool fsi = config->GetFSI_Simulation(); - - if (dual_time) { + if (config->GetTime_Domain()) DualTime_Derivative.resize(nPoint,nVar) = su2double(0.0); - DualTime_Derivative_n.resize(nPoint,nVar) = su2double(0.0); - Solution_time_n.resize(nPoint,nVar) = su2double(0.0); - Solution_time_n1.resize(nPoint,nVar) = su2double(0.0); - } + if (config->GetTime_Marching() != TIME_MARCHING::STEADY) + DualTime_Derivative_n.resize(nPoint,nVar) = su2double(0.0); Solution_Direct.resize(nPoint,nVar); Sensitivity.resize(nPoint,nDim) = su2double(0.0); @@ -51,18 +43,9 @@ CDiscAdjVariable::CDiscAdjVariable(const su2double* sol, unsigned long npoint, u for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) for (unsigned long iVar = 0; iVar < nVar; ++iVar) Solution(iPoint,iVar) = sol[iVar]; - - if (fsi) { - Geometry_Direct.resize(nPoint,nDim) = su2double(0.0); - Solution_Geometry.resize(nPoint,nDim) = su2double(1e-16); - Solution_Geometry_Old.resize(nPoint,nDim) = su2double(0.0); - - Solution_Geometry_BGS_k.resize(nPoint,nDim) = su2double(0.0); - } - - if (config->GetMultizone_Problem() && config->GetDiscrete_Adjoint()) { - External.resize(nPoint,nVar) = su2double(0.0); - } } -void CDiscAdjVariable::Set_OldSolution_Geometry() { Solution_Geometry_Old = Solution_Geometry; } +void CDiscAdjVariable::Set_External_To_DualTimeDer() { + assert(External.size() == DualTime_Derivative.size()); + parallelCopy(External.size(), DualTime_Derivative.data(), External.data()); +} diff --git a/SU2_CFD/src/variables/CFEAVariable.cpp b/SU2_CFD/src/variables/CFEAVariable.cpp index 9b712360486..abe6e408ba9 100644 --- a/SU2_CFD/src/variables/CFEAVariable.cpp +++ b/SU2_CFD/src/variables/CFEAVariable.cpp @@ -25,22 +25,33 @@ * License along with SU2. If not, see . */ - #include "../../include/variables/CFEAVariable.hpp" - -CFEAVariable::CFEAVariable(const su2double *val_fea, unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config) - : CVariable(npoint, ndim, nvar, config) { - - bool nonlinear_analysis = (config->GetGeometricConditions() == STRUCT_DEFORMATION::LARGE); - bool body_forces = config->GetDeadLoad(); - bool incremental_load = config->GetIncrementalLoad(); - bool prestretch_fem = config->GetPrestretch(); // Structure is prestretched - bool discrete_adjoint = config->GetDiscrete_Adjoint(); - bool refgeom = config->GetRefGeom(); // Reference geometry needs to be stored - bool dynamic_analysis = config->GetTime_Domain(); - bool multizone = config->GetMultizone_Problem(); - bool fsi_analysis = config->GetFSI_Simulation() || multizone; +CFEAVariable::CFEAVariable(const su2double *val_fea, unsigned long npoint, unsigned long ndim, + unsigned long nvar, CConfig *config) : + CVariable(npoint, ndim, config->GetTime_Domain()? 3*nvar : nvar, config) { + + /*--- In time domain CVariable::nVar is mult. by 3 ^^^ (for vel. and accel.) + * and the original value then restored (below). ---*/ + nVar = nvar; + /*--- This simplifies the discrete adjoint of this solver, as it allows an abstract + * treatment of the "state" (disp. vel. accel.) whose details are only important + * for the primal solver. In time domain the primal "believes" it has nVar variables, + * which it uses for linear solvers, and then handles velocity and acceleration + * explicitly (for time integration). Whereas the discrete adjoint "thinks" the + * primal solution has 3*nVar variables. This is a little different from simply + * giving names to parts of the solution, it requires the methods of CVariable that + * deal with adjoints to deduce "nVar" from the container, rather than relying on + * the nVar member (which is manipulated above, so that CVariable::SetSolution, etc. + * still work as expected for the primal solver). ---*/ + + const bool dynamic_analysis = config->GetTime_Domain(); + const bool body_forces = config->GetDeadLoad(); + const bool prestretch_fem = config->GetPrestretch(); // Structure is prestretched + const bool discrete_adjoint = config->GetDiscrete_Adjoint(); + const bool refgeom = config->GetRefGeom(); // Reference geometry needs to be stored + const bool multizone = config->GetMultizone_Problem(); + const bool fsi_analysis = config->GetFSI_Simulation() || multizone; VonMises_Stress.resize(nPoint) = su2double(0.0); @@ -52,33 +63,28 @@ CFEAVariable::CFEAVariable(const su2double *val_fea, unsigned long npoint, unsig for (unsigned long iVar = 0; iVar < nVar; iVar++) Solution(iPoint,iVar) = val_fea[iVar]; + if (fsi_analysis) { + Solution_Pred.resize(nPoint,nVar); + Solution_Pred_Old.resize(nPoint,nVar); + + for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) + for (unsigned long iVar = 0; iVar < nVar; iVar++) + Solution_Pred(iPoint,iVar) = Solution_Pred_Old(iPoint,iVar) = val_fea[iVar]; + } + if (dynamic_analysis) { - Solution_Vel.resize(nPoint,nVar); - Solution_Accel.resize(nPoint,nVar); + if (fsi_analysis) Solution_Vel_Pred.resize(nPoint,nVar); for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) { for (unsigned long iVar = 0; iVar < nVar; iVar++) { - Solution_Vel(iPoint,iVar) = val_fea[iVar+nVar]; - Solution_Accel(iPoint,iVar) = val_fea[iVar+2*nVar]; + Solution_Vel_time_n(iPoint,iVar) = Solution_Vel(iPoint,iVar) = val_fea[iVar+nVar]; + Solution_Accel_time_n(iPoint,iVar) = Solution_Accel(iPoint,iVar) = val_fea[iVar+2*nVar]; + if (fsi_analysis) Solution_Vel_Pred(iPoint,iVar) = val_fea[iVar+nVar]; } } - Solution_Vel_time_n = Solution_Vel; - Solution_Accel_time_n = Solution_Accel; } - if (fsi_analysis) { - Solution_Pred = Solution; - Solution_Pred_Old = Solution; - if (dynamic_analysis) Solution_Vel_Pred = Solution_Vel; - } - - /*--- If we are going to use incremental analysis, we need a way to store the old solution ---*/ - - if (incremental_load && nonlinear_analysis) Solution_Old.resize(nPoint,nVar) = su2double(0.0); - - /*--- If we are running a discrete adjoint iteration, we need this vector for cross-dependencies ---*/ - - else if (discrete_adjoint && fsi_analysis) Solution_Old = Solution; + if (discrete_adjoint && fsi_analysis) Solution_Old = Solution; /*--- Body residual ---*/ if (body_forces) Residual_Ext_Body.resize(nPoint,nVar) = su2double(0.0); @@ -94,51 +100,3 @@ CFEAVariable::CFEAVariable(const su2double *val_fea, unsigned long npoint, unsig AuxVar.resize(nPoint); } } - -void CFEAVariable::SetSolution_Vel_time_n() { Solution_Vel_time_n = Solution_Vel; } - -void CFEAVariable::SetSolution_Accel_time_n() { Solution_Accel_time_n = Solution_Accel; } - -void CFEAVariable::Register_femSolution_time_n() { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_time_n(iPoint,iVar)); -} - -void CFEAVariable::RegisterSolution_Vel(bool input) { - if (input) { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_Vel(iPoint,iVar)); - } - else { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterOutput(Solution_Vel(iPoint,iVar)); - } -} - -void CFEAVariable::RegisterSolution_Vel_time_n() { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_Vel_time_n(iPoint,iVar)); -} - -void CFEAVariable::RegisterSolution_Accel(bool input) { - if (input) { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_Accel(iPoint,iVar)); - } - else { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterOutput(Solution_Accel(iPoint,iVar)); - } -} - -void CFEAVariable::RegisterSolution_Accel_time_n() { - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Solution_Accel_time_n(iPoint,iVar)); -} diff --git a/SU2_CFD/src/variables/CMeshBoundVariable.cpp b/SU2_CFD/src/variables/CMeshBoundVariable.cpp index 9460543d374..3330f7e885d 100644 --- a/SU2_CFD/src/variables/CMeshBoundVariable.cpp +++ b/SU2_CFD/src/variables/CMeshBoundVariable.cpp @@ -25,7 +25,6 @@ * License along with SU2. If not, see . */ - #include "../../include/variables/CMeshBoundVariable.hpp" CMeshBoundVariable::CMeshBoundVariable(unsigned long npoint, unsigned long ndim, CConfig *config) : @@ -48,15 +47,8 @@ void CMeshBoundVariable::AllocateBoundaryVariables(CConfig *config) { if (config->GetTime_Domain()) Boundary_Velocity.resize(nBoundPt,nDim) = su2double(0.0); } -void CMeshBoundVariable::Register_BoundDisp(bool input) { - if (input) { - for (unsigned long iVertex = 0; iVertex < Boundary_Displacement.rows(); iVertex++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterInput(Boundary_Displacement(iVertex,iVar)); - } - else { - for (unsigned long iVertex = 0; iVertex < Boundary_Displacement.rows(); iVertex++) - for (unsigned long iVar = 0; iVar < nVar; iVar++) - AD::RegisterOutput(Boundary_Displacement(iVertex,iVar)); - } +void CMeshBoundVariable::Register_BoundDisp() { + for (unsigned long iVertex = 0; iVertex < Boundary_Displacement.rows(); iVertex++) + for (unsigned long iVar = 0; iVar < nVar; iVar++) + AD::RegisterInput(Boundary_Displacement(iVertex,iVar)); } diff --git a/SU2_CFD/src/variables/CMeshVariable.cpp b/SU2_CFD/src/variables/CMeshVariable.cpp index d4786c3ed75..143c0f1188f 100644 --- a/SU2_CFD/src/variables/CMeshVariable.cpp +++ b/SU2_CFD/src/variables/CMeshVariable.cpp @@ -31,9 +31,6 @@ CMeshVariable::CMeshVariable(unsigned long npoint, unsigned long ndim, CConfig *config) : CVariable(npoint, ndim, config) { - /*--- Booleans that determine the kind of problems ---*/ - bool time_domain = config->GetTime_Domain(); - /*--- Store the dimensionality of the problem ---*/ nDim = ndim; @@ -42,25 +39,12 @@ CMeshVariable::CMeshVariable(unsigned long npoint, unsigned long ndim, CConfig * WallDistance.resize(nPoint) = su2double(1e-9); /*--- Initialize the variables necessary when the problem is time domain ---*/ - if (time_domain) { + if (config->GetTime_Domain()) { Solution_time_n.resize(nPoint,nDim) = su2double(0.0); Solution_time_n1.resize(nPoint,nDim) = su2double(0.0); } } -void CMeshVariable::Register_MeshCoord(bool input) { - if (input) { - SU2_OMP_FOR_STAT(roundUpDiv(nPoint,omp_get_num_threads())) - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iDim = 0; iDim < nDim; iDim++) - AD::RegisterInput(Mesh_Coord(iPoint,iDim)); - END_SU2_OMP_FOR - } - else { - SU2_OMP_FOR_STAT(roundUpDiv(nPoint,omp_get_num_threads())) - for (unsigned long iPoint = 0; iPoint < nPoint; iPoint++) - for (unsigned long iDim = 0; iDim < nDim; iDim++) - AD::RegisterOutput(Mesh_Coord(iPoint,iDim)); - END_SU2_OMP_FOR - } +void CMeshVariable::Register_MeshCoord() { + RegisterContainer(true, Mesh_Coord); } diff --git a/SU2_CFD/src/variables/CVariable.cpp b/SU2_CFD/src/variables/CVariable.cpp index 84842a77ee5..78e6ae7b59d 100644 --- a/SU2_CFD/src/variables/CVariable.cpp +++ b/SU2_CFD/src/variables/CVariable.cpp @@ -46,7 +46,7 @@ CVariable::CVariable(unsigned long npoint, unsigned long nvar, CConfig *config) } -CVariable::CVariable(unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config) { +CVariable::CVariable(unsigned long npoint, unsigned long ndim, unsigned long nvar, CConfig *config, bool adjoint) { /*--- Initializate the number of dimension and number of variables ---*/ nPoint = npoint; @@ -59,17 +59,20 @@ CVariable::CVariable(unsigned long npoint, unsigned long ndim, unsigned long nva Solution_Old.resize(nPoint,nVar) = su2double(0.0); - if (config->GetTime_Marching() != TIME_MARCHING::STEADY) { - Solution_time_n.resize(nPoint,nVar); - Solution_time_n1.resize(nPoint,nVar); - } - else if (config->GetTime_Domain()) { + if (config->GetTime_Domain()) Solution_time_n.resize(nPoint,nVar) = su2double(0.0); - } - if(config->GetMultizone_Problem() && config->GetAD_Mode()) { - AD_InputIndex.resize(nPoint,nVar) = -1; - AD_OutputIndex.resize(nPoint,nVar) = -1; + if (config->GetTime_Marching() != TIME_MARCHING::STEADY) + Solution_time_n1.resize(nPoint,nVar) = su2double(0.0); + + if (config->GetDiscrete_Adjoint()) { + if (adjoint && config->GetMultizone_Problem()) + External.resize(nPoint,nVar) = su2double(0.0); + + if (!adjoint) { + AD_InputIndex.resize(nPoint,nVar) = -1; + AD_OutputIndex.resize(nPoint,nVar) = -1; + } } if (config->GetMultizone_Problem()) @@ -108,41 +111,14 @@ void CVariable::Restore_BGSSolution_k() { void CVariable::SetExternalZero() { parallelSet(External.size(), 0.0, External.data()); } -void CVariable::RegisterSolution(bool input, bool push_index) { - SU2_OMP_FOR_STAT(roundUpDiv(nPoint,omp_get_num_threads())) - for (unsigned long iPoint = 0; iPoint < nPoint; ++iPoint) { - for(unsigned long iVar=0; iVarGetnMarker_All(); nDim = geometry->GetnDim(); nDV = config->GetnDV(); - VarCoord = nullptr; - /*--- Discrete adjoint gradient computation ---*/ if (rank == MASTER_NODE) @@ -712,21 +710,13 @@ void SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *su /*--- Register design variables as input and set them to zero * (since we want to have the derivative at alpha = 0, i.e. for the current design) ---*/ - - for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - - for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ + for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ - /*--- Initilization with su2double resets the index ---*/ + config->SetDV_Value(iDV, iDV_Value, 0.0); - DV_Value = 0.0; - - AD::RegisterInput(DV_Value); - - config->SetDV_Value(iDV, iDV_Value, DV_Value); + AD::RegisterInput(config->GetDV_Value(iDV, iDV_Value)); } } @@ -742,10 +732,7 @@ void SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *su * We need that to make sure to set the sensitivity of surface points only once * (Markers share points, so we would visit them more than once in the loop over the markers below) ---*/ - bool* visited = new bool[geometry->GetnPoint()]; - for (iPoint = 0; iPoint < geometry->GetnPoint(); iPoint++){ - visited[iPoint] = false; - } + vector visited(geometry->GetnPoint(), false); /*--- Initialize the derivatives of the output of the surface deformation routine * with the discrete adjoints from the CFD solution ---*/ @@ -779,18 +766,16 @@ void SetProjection_AD(CGeometry *geometry, CConfig *config, CSurfaceMovement *su } } - delete [] visited; - /*--- Compute derivatives and extract gradient ---*/ AD::ComputeAdjoint(); for (iDV = 0; iDV < nDV; iDV++){ - nDV_Value = config->GetnDV_Value(iDV); - for (iDV_Value = 0; iDV_Value < nDV_Value; iDV_Value++){ - DV_Value = config->GetDV_Value(iDV, iDV_Value); - my_Gradient = SU2_TYPE::GetDerivative(DV_Value); + for (iDV_Value = 0; iDV_Value < config->GetnDV_Value(iDV); iDV_Value++){ + + my_Gradient = SU2_TYPE::GetDerivative(config->GetDV_Value(iDV, iDV_Value)); + SU2_MPI::Allreduce(&my_Gradient, &localGradient, 1, MPI_DOUBLE, MPI_SUM, SU2_MPI::GetComm()); /*--- Angle of Attack design variable (this is different, diff --git a/SU2_PY/FSI_tools/FSIInterface.py b/SU2_PY/FSI_tools/FSIInterface.py index 2b1e167d79b..70f0f164b15 100644 --- a/SU2_PY/FSI_tools/FSIInterface.py +++ b/SU2_PY/FSI_tools/FSIInterface.py @@ -1900,8 +1900,8 @@ def UnsteadyFSI(self,FSI_config, FluidSolver, SolidSolver): if FSI_config['RESTART_SOL'] == 'YES': NbTimeIter = ((totTime)/deltaT)-1 - time = (FSI_config['RESTART_ITER']+1)*deltaT - TimeIter = FSI_config['RESTART_ITER']+1 + time = (FSI_config['RESTART_ITER'])*deltaT + TimeIter = FSI_config['RESTART_ITER'] else: NbTimeIter = (totTime/deltaT)-1 # number of time iterations time = 0.0 # initial time @@ -1922,13 +1922,6 @@ def UnsteadyFSI(self,FSI_config, FluidSolver, SolidSolver): TimeIterTreshold = -1 self.getSolidInterfaceDisplacement(SolidSolver) self.displacementPredictor(FSI_config, SolidSolver, deltaT) - # We need now to update the solution because both restarter functions (solid and fluid) - # load the files in the solution containers, pushing back the previous solutions. We need - # then to push it back once more to compute the solution at the next time level - # Also this is required because in the fluid iteration preprocessor, if we do not update - # and step to the next time level, there is a flag "fsi" that will initialise the flow - if myid in self.fluidSolverProcessors: - FluidSolver.Update() if myid in self.solidSolverProcessors: SolidSolver.updateSolution() #If no restart diff --git a/SU2_PY/FSI_tools/FSI_config.py b/SU2_PY/FSI_tools/FSI_config.py index aad28ff0ee1..6a1dc3f88d0 100644 --- a/SU2_PY/FSI_tools/FSI_config.py +++ b/SU2_PY/FSI_tools/FSI_config.py @@ -122,3 +122,6 @@ def applyDefaults(self): if self._ConfigContent["CSD_SOLVER"] == "IMPOSED": self._ConfigContent["AITKEN_RELAX"] = "STATIC" self._ConfigContent["AITKEN_PARAM"] = 1.0 + + if self._ConfigContent["RESTART_SOL"] == "YES": + self._ConfigContent["TIME_TRESHOLD"] = -1 diff --git a/SU2_PY/SU2_Nastran/pysu2_nastran.py b/SU2_PY/SU2_Nastran/pysu2_nastran.py index 6c9aebe1d2c..1994ec7b512 100644 --- a/SU2_PY/SU2_Nastran/pysu2_nastran.py +++ b/SU2_PY/SU2_Nastran/pysu2_nastran.py @@ -722,7 +722,7 @@ def __computeInterfacePosVel(self, initialize): Y_disp = self.Uy.dot(self.q) Z_disp = self.Uz.dot(self.q) - for iPoint in range(len(self.node)): + for iPoint in range(self.nPoint): coord0 = self.node[iPoint].GetCoord0() self.node[iPoint].SetCoord((X_disp[iPoint]+coord0[0],Y_disp[iPoint]+coord0[1],Z_disp[iPoint]+coord0[2])) self.node[iPoint].SetVel((X_vel[iPoint],Y_vel[iPoint],Z_vel[iPoint])) @@ -870,7 +870,7 @@ def __setRestart(self, timeIter): print("The restart iteration was not found in the structural history") break line = line.strip('\r\n').split() - if int(line[1])==(self.Config["RESTART_ITER"]-1): + if int(line[1])==(self.Config["RESTART_ITER"]-2): break index = 0 for index_mode in range(self.nDof): @@ -896,7 +896,7 @@ def __setRestart(self, timeIter): print("The restart iteration was not found in the structural history") break line = line.strip('\r\n').split() - if int(line[1])==self.Config["RESTART_ITER"]: + if int(line[1])==(self.Config["RESTART_ITER"]-1): break index = 0 for index_mode in range(self.nDof): @@ -935,11 +935,7 @@ def updateSolution(self): self.__reset(self.qddot) self.__reset(self.a) - makerID = list(self.markers.keys()) - makerID = makerID[0] - nodeList = self.markers[makerID] - - for iPoint in nodeList: + for iPoint in range(self.nPoint): self.node[iPoint].updateCoordVel() diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/O_mesh_cylinder.geo b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/O_mesh_cylinder.geo new file mode 100644 index 00000000000..b048536e342 --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/O_mesh_cylinder.geo @@ -0,0 +1,147 @@ +// ----------------------------------------------------------------------------------- // +// Kattmann 20.08.2018, O mesh for CHT vortex shedding behind cylinder +// The O mesh around the cylinder consists out of two half cylinders. +// The inner pin is hollow. +// ----------------------------------------------------------------------------------- // + +// Create fluid and solid mesh seperately and merge together e.g. by hand. + +// Which domain part should be handled +Which_Mesh_Part= 1;// 0=all, 1=Fluid, 2=Solid +// Evoke Meshing Algorithm? +Do_Meshing= 1; // 0=false, 1=true +// Write Mesh files in .su2 format +Write_mesh= 1; // 0=false, 1=true + +//Geometric inputs +cylinder_diameter = 1; +cylinder_radius = cylinder_diameter/2; +mesh_radius = 20 * cylinder_diameter; +inner_pin_d = 0.5; +inner_pin_r = inner_pin_d/2; + +// ----------------------------------------------------------------------------------- // +//Mesh inputs +gridsize = 0.1; +Ncylinder = 40; +Nradial = 50; +Rradial = 1.15; + +NPinRadial = 10; +RPinRadial = 0.91; + +// Each zone is self-sufficient (i.e. has all of its own Points/Lines etc.) +// ----------------------------------------------------------------------------------- // +// Fluid zone +If (Which_Mesh_Part == 0 || Which_Mesh_Part == 1) + + // Geometry definition + // Points + Point(1) = {-mesh_radius, 0, 0, gridsize}; + Point(2) = {-cylinder_radius, 0, 0, gridsize}; + Point(3) = {cylinder_radius, 0, 0, gridsize}; + Point(4) = {mesh_radius, 0, 0, gridsize}; + Point(5) = {0, 0, 0, gridsize}; + + //helping point to know height of first layer + //Point(6) = {-cylinder_radius - 0.002, 0, 0, gridsize}; + + // Lines + Line(1) = {1, 2}; // to the left + Line(2) = {3, 4}; // to the right + + Circle(3) = {2, 5, 3}; // lower inner + Circle(4) = {1, 5, 4}; // lower outer + Circle(5) = {3, 5, 2}; // upper inner + Circle(6) = {4, 5, 1}; // upper outer + + // Lineloops and surfaces + Line Loop(1) = {1, 3, 2, -4}; Plane Surface(1) = {1}; // lower half cylinder + Line Loop(2) = {1, -5, 2, 6}; Plane Surface(2) = {2}; // upper half cylinder + + // ----------------------------------------------------------------------------------- // + // Mesh definition + // make structured mesh with transfinite Lines + + // lower + Transfinite Line{3, 4} = Ncylinder; + Transfinite Line{-1, 2} = Nradial Using Progression Rradial; + + // upper + Transfinite Line{-5, -6} = Ncylinder; + Transfinite Line{-1, 2} = Nradial Using Progression Rradial; + + // Physical Groups + Physical Line("cylinder_fluid") = {3, 5}; + Physical Line("farfield") = {4, 6}; + Physical Surface("surface_mesh") = {1, 2}; + +EndIf + +// ----------------------------------------------------------------------------------- // +// Pin zone +If (Which_Mesh_Part == 0 || Which_Mesh_Part == 2) + + // Geometry definition + // Points + Point(11) = {-cylinder_radius, 0, 0, gridsize}; + Point(12) = {-inner_pin_r, 0, 0, gridsize}; + Point(13) = {inner_pin_r, 0, 0, gridsize}; + Point(14) = {cylinder_radius, 0, 0, gridsize}; + Point(15) = {0, 0, 0, gridsize}; + + // Lines + Line(11) = {11, 12}; // to the left + Line(12) = {13, 14}; // to the right + + Circle(13) = {12, 15, 13}; // lower inner + Circle(14) = {11, 15, 14}; // lower outer + Circle(15) = {13, 15, 12}; // upper inner + Circle(16) = {14, 15, 11}; // upper outer + + // Lineloops and surfaces + Line Loop(11) = {11, 13, 12, -14}; Plane Surface(11) = {11}; // lower half cylinder + Line Loop(12) = {11, -15, 12, 16}; Plane Surface(12) = {12}; // upper half cylinder + + // ----------------------------------------------------------------------------------- // + // Mesh definition + // make structured mesh with transfinite Lines + + // lower + Transfinite Line{13, 14} = Ncylinder; + Transfinite Line{-11, 12} = NPinRadial Using Progression RPinRadial; + + // upper + Transfinite Line{-15, -16} = Ncylinder; + Transfinite Line{-11, 12} = NPinRadial Using Progression RPinRadial; + + // Physical Groups + Physical Line("inner_pin") = {13, 15}; + Physical Line("cylinder_solid") = {14, 16}; + Physical Surface("surface_mesh") = {11, 12}; + +EndIf + +// ----------------------------------------------------------------------------------- // +Transfinite Surface "*"; +Recombine Surface "*"; + +If (Do_Meshing == 1) + Mesh 1; Mesh 2; +EndIf + +// ----------------------------------------------------------------------------------- // +// Write .su2 meshfile +If (Write_mesh == 1) + + Mesh.Format = 42; // .su2 mesh format, + If (Which_Mesh_Part == 1) + Save "fluid.su2"; + ElseIf (Which_Mesh_Part == 2) + Save "solid.su2"; + Else + Printf("Invalid Which_Mesh_Part variable."); + Abort; + EndIf + +EndIf diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/README.md b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/README.md new file mode 100644 index 00000000000..7023e981943 --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/README.md @@ -0,0 +1,30 @@ +# Unsteady CHT Adjoint Testcase + +## Short Description +This is a 2D cylinder in freestream testcase. The flow is incompressible and laminar at Re=200. +A uniform vortex shedding forms behind the cylinder and each shedding cycle is resolved by 54 timesteps. +The pin is heated on the inner surface. + +## Mesh +The mesh is for testing purposes only and contains ~4000 elements for the flow and ~1000 for the heat domain. +A gmsh .geo file is added such that the mesh can be recreated and modified. + +## Recreating full primal +The primal for a full cycle can be restarted with the `solution_*_00000.dat` and `solution_*_00001.dat`. +The primal solution is necessary for the Discrete Adjoint sweep and for the gradient of the full +shedding cycle the full primal is necessary. The necessary changes to `chtMaster.cfg` are documented +in the config itself. + +## Discrete Adjoint +In the regression testcase of SU2 only 2 reverse steps are taken. +For that, the solution files 52-55 for the adjoint are added. +The objective Function is the average temperature on the inner pin surface, averaged over the full time. + +## Gradient validation via Finite Differences using FADO +In order to validate the Discrete Adjoint gradient a Finite Differences python script `gradient_validation.py` +using [FADO](www.github.com/su2code/FADO) is added. +Note that the script can be used with the files as they are. Necessary adaptions are made by FADO itself. +The script deforms the mesh and runs the primal for each of the 18 Design Variables. +Afterwards the baseline mesh is evaluated and then the Discrete Adjoint. +Use `postprocess.py` to print the absolute difference and relative difference in percent to screen. +The relative differences in percent are <0.15% for all Design Variables (2021-05-14). diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/chtMaster.cfg b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/chtMaster.cfg new file mode 100644 index 00000000000..a32ece5723b --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/chtMaster.cfg @@ -0,0 +1,151 @@ +% 2021-03-11 TobiKattmann +% +SOLVER= MULTIPHYSICS +% +% Set RESTART_SOL=YES for primal runs including the FD sweep +RESTART_SOL= NO +RESTART_ITER= 2 +READ_BINARY_RESTART= YES +SOLUTION_FILENAME= solution +RESTART_FILENAME= solution +% +CONFIG_LIST = ( fluid.cfg, solid.cfg ) +% +MARKER_ZONE_INTERFACE= ( cylinder_fluid, cylinder_solid ) +MARKER_CHT_INTERFACE= ( cylinder_fluid, cylinder_solid ) +% +% ------------------------- UNSTEADY SIMULATION -------------------------------% +% +TIME_DOMAIN= YES +TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER +% +TIME_STEP= 500 +% +MAX_TIME= 1e9 +% For a primal restart change TIME_ITER=56 for the correct number of steps. 54 is for the adjoint run. +TIME_ITER= 54 +% For the primal (and therefore FD sweep) OUTER_ITER=200 is suitable. +% For an accurate adjont run set OUTER_ITER=500. 100 is for the regression test. +OUTER_ITER= 100 +%INNER_ITER= 1 +% +UNST_ADJOINT_ITER= 56 +% +ITER_AVERAGE_OBJ= 54 +% +% ------------------------- INPUT/OUTPUT FILE INFORMATION --------------------------% +% +MESH_FILENAME= MeshCHT.su2 +% +SCREEN_OUTPUT= (TIME_ITER, OUTER_ITER, BGS_ADJ_PRESSURE[0], BGS_ADJ_VELOCITY-X[0], BGS_ADJ_VELOCITY-Y[0], BGS_ADJ_TEMPERATURE[0], BGS_ADJ_TEMPERATURE[1], SENS_TEMP[0], SENS_GEO[0], SENS_GEO[1] ) +% Suitable output for primal simulations +%SCREEN_OUTPUT= (TIME_ITER, OUTER_ITER, WALL_TIME, BGS_PRESSURE[0], BGS_TEMPERATURE[0], BGS_TEMPERATURE[1], DRAG[0], AVG_TEMPERATURE[1] ) +SCREEN_WRT_FREQ_OUTER= 50 +% +HISTORY_OUTPUT= ( ITER, BGS_RES[0], RMS_RES[0], BGS_RES[1], RMS_RES[1],\ + FLOW_COEFF[0], HEAT[0], AERO_COEFF[0], HEAT[1],\ + LINSOL[0], LINSOL[1], TAVG_HEAT[1]) +% +OUTPUT_FILES= (RESTART, PARAVIEW) +OUTPUT_WRT_FREQ= 1 +VOLUME_FILENAME= flow +WRT_PERFORMANCE= YES +% +SOLUTION_ADJ_FILENAME= solution_adj +RESTART_ADJ_FILENAME= solution_adj +VOLUME_ADJ_FILENAME= flow_adj +% +TABULAR_FORMAT= CSV +GRAD_OBJFUNC_FILENAME= of_grad.csv +OUTPUT_PRECISION=16 +% +% -------------------- FREE-FORM DEFORMATION PARAMETERS -----------------------% +% +FFD_TOLERANCE= 1E-10 +FFD_ITERATIONS= 500 +% +% FFD box definition: 2D case (FFD_BoxTag, X1, Y1, 0.0, X2, Y2, 0.0, X3, Y3, 0.0, X4, Y4, 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) +% Counterclockwise definition of FFD cornerpoints +FFD_DEFINITION= (BOX,\ + -0.6,-0.6,0.0,\ + 0.6,-0.6,0.0,\ + 0.6, 0.6,0.0,\ + -0.6, 0.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 ) +% +% FFD box degree: 2D case (x_degree, y_degree, 0) +FFD_DEGREE= (8, 1, 0) +% +% Surface grid continuity at the intersection with the faces of the FFD boxes. +% To keep a particular level of surface continuity, SU2 automatically freezes the right +% number of control point planes (NO_DERIVATIVE, 1ST_DERIVATIVE, 2ND_DERIVATIVE, USER_INPUT) +FFD_CONTINUITY= NO_DERIVATIVE +% +% ----------------------- DESIGN VARIABLE PARAMETERS --------------------------% +% +%DV_KIND= FFD_SETTING +% First 9 are upper, second 9 are lower DV's +DV_KIND= FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D, FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D,FFD_CONTROL_POINT_2D +% +% Marker of the surface in which we are going apply the shape deformation +DV_MARKER= ( cylinder_fluid, cylinder_solid ) +% +% Parameters of the shape deformation +% - FFD_SETTING ( 1.0 ) +% - FFD_CONTROL_POINT_2D ( FFD_BoxTag, i_Ind, j_Ind, x_Disp, y_Disp ) +%DV_PARAM= ( 1.0 ) +DV_PARAM= \ +( BOX, 0, 1, 0.0, 1.0);\ +( BOX, 1, 1, 0.0, 1.0);\ +( BOX, 2, 1, 0.0, 1.0);\ +( BOX, 3, 1, 0.0, 1.0);\ +( BOX, 4, 1, 0.0, 1.0);\ +( BOX, 5, 1, 0.0, 1.0);\ +( BOX, 6, 1, 0.0, 1.0);\ +( BOX, 7, 1, 0.0, 1.0);\ +( BOX, 8, 1, 0.0, 1.0);\ +( BOX, 0, 0, 0.0, 1.0);\ +( BOX, 1, 0, 0.0, 1.0);\ +( BOX, 2, 0, 0.0, 1.0);\ +( BOX, 3, 0, 0.0, 1.0);\ +( BOX, 4, 0, 0.0, 1.0);\ +( BOX, 5, 0, 0.0, 1.0);\ +( BOX, 6, 0, 0.0, 1.0);\ +( BOX, 7, 0, 0.0, 1.0);\ +( BOX, 8, 0, 0.0, 1.0) +% +% Value of the shape deformation +DV_VALUE= 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0, 1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0,1.0 +% +% ------------------------ GRID DEFORMATION PARAMETERS ------------------------% +% +DEFORM_LINEAR_SOLVER= FGMRES +DEFORM_LINEAR_SOLVER_PREC= ILU +DEFORM_LINEAR_SOLVER_ERROR= 1E-14 +DEFORM_NONLINEAR_ITER= 1 +DEFORM_LINEAR_SOLVER_ITER= 1000 +% +DEFORM_CONSOLE_OUTPUT= YES +DEFORM_STIFFNESS_TYPE= WALL_DISTANCE +% +DEFINITION_DV= \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 0, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 1, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 2, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 3, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 4, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 5, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 6, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 7, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 8, 1, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 0, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 1, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 2, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 3, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 4, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 5, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 6, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 7, 0, 0.0, 1.0 ); \ +( 19, 1.0 | cylinder_fluid, cylinder_solid | BOX, 8, 0, 0.0, 1.0 ) + diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/fluid.cfg b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/fluid.cfg new file mode 100644 index 00000000000..b4fe5b28efb --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/fluid.cfg @@ -0,0 +1,80 @@ +% TobiKattmann 2021-03-11 +% +SOLVER= INC_NAVIER_STOKES +% +OBJECTIVE_FUNCTION= AVG_TEMPERATURE +%OBJECTIVE_FUNCTION= DRAG +OBJECTIVE_WEIGHT= 0.0 +% +% ---------------- INCOMPRESSIBLE FLOW CONDITION DEFINITION -------------------% +% +INC_NONDIM= DIMENSIONAL +% ~Water at room temperature +INC_DENSITY_MODEL= CONSTANT +INC_DENSITY_INIT= 1.0e3 +% +% Re = rho*v*d/mu_dyn = 1e3*v*1/1e-3 = 200 => v = 2.0e-4 +INC_VELOCITY_INIT= ( 2.0e-4, 0.0, 0.0 ) +% +INC_ENERGY_EQUATION= YES +INC_TEMPERATURE_INIT= 288.15 +SPECIFIC_HEAT_CP= 4180 +% +VISCOSITY_MODEL= CONSTANT_VISCOSITY +MU_CONSTANT= 1.0e-3 +% +% Pr = c_p * mu_dyn / lambda +% lambda_water = 0.6 => Pr = 4180 * 1e-3 / 0.6 = 6.96 +CONDUCTIVITY_MODEL= CONSTANT_PRANDTL +PRANDTL_LAM = 6.96 +% +% -------------------- BOUNDARY CONDITION DEFINITION --------------------------% +% +MARKER_FAR= ( farfield ) +%MARKER_HEATFLUX= ( cylinder_fluid, 1e2 ) +% +% ------------- COMMON PARAMETERS DEFINING THE NUMERICAL METHOD ---------------% +% +NUM_METHOD_GRAD= GREEN_GAUSS +% +CFL_NUMBER= 1e3 +CFL_ADAPT= NO +CFL_ADAPT_PARAM= ( 0.8, 1.4, 10.0, 1e10, 0.001 ) +% +RK_ALPHA_COEFF= ( 0.66667, 0.66667, 1.000000 ) +% +% ------------------------ LINEAR SOLVER DEFINITION ---------------------------% +% +LINEAR_SOLVER= FGMRES +LINEAR_SOLVER_PREC= ILU +%LINEAR_SOLVER_ERROR= 1E-4 +LINEAR_SOLVER_ERROR= 1E-8 +LINEAR_SOLVER_ITER= 20 +% +CONV_NUM_METHOD_FLOW= FDS +MUSCL_FLOW= YES +SLOPE_LIMITER_FLOW= NONE +TIME_DISCRE_FLOW= EULER_IMPLICIT +% +% --------------------------- CONVERGENCE PARAMETERS --------------------------% +% +CONV_RESIDUAL_MINVAL= -20 +CONV_STARTITER= 2000 +CONV_CAUCHY_ELEMS= 100 +CONV_CAUCHY_EPS= 1E-6 +% +% ------------------------- INPUT/OUTPUT INFORMATION --------------------------% +% +%MESH_FILENAME= fluid.su2 +% +%SCREEN_OUTPUT= (TIME_ITER, WALL_TIME, INNER_ITER, RMS_PRESSURE, RMS_VELOCITY-X, DRAG, LIFT, AVG_TEMPERATURE, TOTAL_HEATFLUX ) +%SCREEN_WRT_FREQ_INNER= 100 +% +%HISTORY_OUTPUT= (ITER, RMS_RES, AERO_COEFF, HEAT, FLOW_COEFF, LINSOL) +%HISTORY_WRT_FREQ_INNER= 100 +MARKER_MONITORING= ( cylinder_fluid ) +MARKER_ANALYZE= ( cylinder_fluid ) +MARKER_ANALYZE_AVERAGE= AREA +% +%OUTPUT_FILES= ( RESTART, PARAVIEW ) + diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/gradient_validation.py b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/gradient_validation.py new file mode 100644 index 00000000000..9751520d2be --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/gradient_validation.py @@ -0,0 +1,143 @@ +# FADO script: Finite Differences of unsteady CHT and adjoint run + +from FADO import * + +# Design variables ----------------------------------------------------- # + +nDV = 18 +ffd = InputVariable(0.0,PreStringHandler("DV_VALUE="),nDV) + +# Parameters ----------------------------------------------------------- # + +# The master config `chtMaster.cfg` serves as an SU2 adjoint regression test. +# For a correct gradient validation we need to exchange some options + +time_iter_primal = Parameter(["TIME_ITER= 56"],\ + LabelReplacer("TIME_ITER= 54")) +outer_iter_primal = Parameter(["OUTER_ITER= 200"],\ + LabelReplacer("OUTER_ITER= 100")) +restart_sol_primal = Parameter(["RESTART_SOL= YES"],\ + LabelReplacer("RESTART_SOL= NO")) + +outer_iter_adjoint = Parameter(["OUTER_ITER= 500"],\ + LabelReplacer("OUTER_ITER= 100")) + +# Evaluations ---------------------------------------------------------- # + +# Note that correct SU2 version needs to be in PATH + +def_command = "SU2_DEF chtMaster.cfg" +cfd_command = "mpirun -n 12 SU2_CFD chtMaster.cfg" + +cfd_ad_command = "mpirun -n 12 SU2_CFD_AD chtMaster.cfg" +dot_ad_command = "mpirun -n 12 SU2_DOT_AD chtMaster.cfg" + +max_tries = 1 + +# mesh deformation +deform = ExternalRun("DEFORM",def_command,True) # True means sym links are used for addData +deform.setMaxTries(max_tries) +deform.addConfig("chtMaster.cfg") +deform.addData("fluid.cfg") # zonal cfg's can be symlinked as they are unchanged +deform.addData("solid.cfg") +deform.addData("MeshCHT.su2") +deform.addExpected("mesh_out.su2") + +# direct run +direct = ExternalRun("DIRECT",cfd_command,True) +direct.setMaxTries(max_tries) +direct.addConfig("chtMaster.cfg") +direct.addData("fluid.cfg") +direct.addData("solid.cfg") +direct.addData("DEFORM/mesh_out.su2",destination="MeshCHT.su2") +direct.addData("solution_0_00000.dat") +direct.addData("solution_0_00001.dat") +direct.addData("solution_1_00000.dat") +direct.addData("solution_1_00001.dat") +direct.addExpected("solution_0_00055.dat") +direct.addExpected("solution_1_00055.dat") +direct.addParameter(time_iter_primal) +direct.addParameter(outer_iter_primal) +direct.addParameter(restart_sol_primal) + +# adjoint run +adjoint = ExternalRun("ADJOINT",cfd_ad_command,True) +adjoint.setMaxTries(max_tries) +adjoint.addConfig("chtMaster.cfg") +adjoint.addData("fluid.cfg") # zonal cfg's can be symlinked +adjoint.addData("solid.cfg") +adjoint.addData("DEFORM/mesh_out.su2", destination="MeshCHT.su2") +# add all primal solution files +for timeIter in range(56): # + if timeIter < 10: + timeIter = "0" + str(timeIter) + adjoint.addData("DIRECT/solution_0_000" + str(timeIter) + ".dat") + adjoint.addData("DIRECT/solution_1_000" + str(timeIter) + ".dat") +#end +# replace OUTER_ITER= by 500 and TIME_ITER= 56 +adjoint.addParameter(outer_iter_adjoint) +adjoint.addExpected("solution_adj_avtp_0_00053.dat") +adjoint.addExpected("solution_adj_avtp_1_00053.dat") + +# gradient projection +dot = ExternalRun("DOT",dot_ad_command,True) +dot.setMaxTries(max_tries) +dot.addConfig("chtMaster.cfg") +dot.addData("fluid.cfg") # zonal cfg's can be symlinked +dot.addData("solid.cfg") +dot.addData("DEFORM/mesh_out.su2", destination="MeshCHT.su2") +# add all adjoint solution files +for timeIter in range(54): + if timeIter < 10: + timeIter = "0" + str(timeIter) + dot.addData("ADJOINT/solution_adj_avtp_0_000" + str(timeIter) + ".dat") + dot.addData("ADJOINT/solution_adj_avtp_1_000" + str(timeIter) + ".dat") +#end +dot.addExpected("of_grad.csv") + +# Functions ------------------------------------------------------------ # + +tavgT = Function("tavgT", "DIRECT/chtMaster.csv",LabeledTableReader("\"tavg[AvgTemp[1]]\"")) +tavgT.addInputVariable(ffd,"DOT/of_grad.csv",TableReader(None,0,(1,0))) # all rows, col 0, don't read the header +tavgT.addValueEvalStep(deform) +tavgT.addValueEvalStep(direct) +tavgT.addGradientEvalStep(adjoint) +tavgT.addGradientEvalStep(dot) + +# Driver --------------------------------------------------------------- # + +# The input variable is the constraint tolerance which is not used for our purpose of finite differences +driver = ExteriorPenaltyDriver(0.005) +driver.addObjective("min", tavgT) + +driver.setWorkingDirectory("DOE") +driver.preprocessVariables() +driver.setStorageMode(True,"DESIGN_") + +his = open("doe.his","w",1) +driver.setHistorian(his) + +# Simulation Runs ------------------------------------------------------ # + +# Primal simulation for each deformed DV +for iLoop in range(0, nDV, 1): + print("Computing deformed primal ", iLoop, "/", nDV-1) + x = driver.getInitial() + x[iLoop] = 1e-4 # DV_VALUE + driver.fun(x) +#end + +# Undeformed/initial primal last in order to have the correct solution in +# the WorkindDirectory for the following adjoint +print("Computing baseline primal") +x = driver.getInitial() +driver.fun(x) # baseline evaluation + +# Compute discrete adjoint gradient +print("Computing discrete adjoint gradient") +driver.grad(x) + +his.close() + +# For results run `python postprocess.py` to get screen output +# of the differences between primal and adjoint simulation. diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/postprocess.py b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/postprocess.py new file mode 100644 index 00000000000..bcbe8a7ba2d --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/postprocess.py @@ -0,0 +1,39 @@ +# Compute and print absolute difference between Discrete Adjoint +# and Finite Difference gradient. Prints also percentage difference. +# +# Run this script after `python gradient_validation.py` successfully finished + +import pandas as pd + +# load files +DAgrad = pd.read_csv("DOE/DOT/of_grad.csv") +FDvals = pd.read_csv("doe.his") + +# additional values +nDV = 18 +FDstep = 1e-4 +FDstring = ' tavgT' +DAstring = 'AVG_TEMPERATURE gradient ' + +# create FD gradient +FDgrad = (FDvals[FDstring].iloc[:nDV] - FDvals[FDstring].iloc[nDV]) / FDstep + +# absolute difference +absoluteDiff = DAgrad[DAstring] - FDgrad +print("absolute diff = DAgrad - FDgrad") + +# relative difference in percent +relDiffPercent = (DAgrad[DAstring] - FDgrad)/abs(DAgrad[DAstring]) * 100 +print("relative diff = (DAgrad - FDgrad) / abs(DAgrad) * 100") + + +print('') +print('+-----------+-------------------+-------------------+-------------------+-------------------+') +print('| DV number | DA gradient | FD gradient | absolute diff | relative diff [%] |') +print('+-----------+-------------------+-------------------+-------------------+-------------------+') + +for i_dv in range(0, nDV,1): + print('|{0:10d} |{1:18.10f} |{2:18.10f} |{3:18.10f} |{4:18.10f} |'.format(i_dv, DAgrad[DAstring].iloc[i_dv], FDgrad[i_dv], absoluteDiff[i_dv], relDiffPercent[i_dv])) + +print('+-----------+-------------------+-------------------+-------------------+-------------------+') +print('') diff --git a/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/solid.cfg b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/solid.cfg new file mode 100644 index 00000000000..8af4dae4a7d --- /dev/null +++ b/TestCases/coupled_cht/disc_adj_unsteadyCHT_cylinder/solid.cfg @@ -0,0 +1,59 @@ +% 2021-03-11 TobiKattmann +% +SOLVER= HEAT_EQUATION +% +OBJECTIVE_FUNCTION= AVG_TEMPERATURE +%OBJECTIVE_FUNCTION= DRAG +OBJECTIVE_WEIGHT= 1.0 +% +% ---------------- (SOLIDS) CONDUCTION CONDITION DEFINITION -------------------% +% +% ~Aluminium at room temperature +INC_NONDIM= DIMENSIONAL +% +SOLID_TEMPERATURE_INIT= 340.0 +SOLID_DENSITY= 2719 +SPECIFIC_HEAT_CP = 0.8710 +SOLID_THERMAL_CONDUCTIVITY= 200 +% +% -------------------- BOUNDARY CONDITION DEFINITION --------------------------% +% +MARKER_HEATFLUX= ( inner_pin, 1e3 ) +% +% ------------- COMMON PARAMETERS DEFINING THE NUMERICAL METHOD ---------------% +% +NUM_METHOD_GRAD= GREEN_GAUSS +% +CFL_NUMBER= 1e4 +CFL_ADAPT= NO +CFL_ADAPT_PARAM= ( 0.1, 2.0, 10.0, 1e10, 0.001 ) +% +BETA_FACTOR= 50 +MAX_DELTA_TIME= 1.0 +% +% ------------------------ LINEAR SOLVER DEFINITION ---------------------------% +% +LINEAR_SOLVER= FGMRES +LINEAR_SOLVER_PREC= ILU +LINEAR_SOLVER_ERROR= 1E-15 +LINEAR_SOLVER_ITER= 20 +% +% --------------------------- CONVERGENCE PARAMETERS --------------------------% +% +CONV_RESIDUAL_MINVAL= -20 +CONV_STARTITER= 10000 +% +% -------------------- HEAT NUMERICAL METHOD DEFINITION -----------------------% +% +CONV_NUM_METHOD_HEAT = SPACE_CENTERED +TIME_DISCRE_HEAT= EULER_IMPLICIT +% +% ------------------------- INPUT/OUTPUT INFORMATION --------------------------% +% +%MESH_FILENAME= solid.su2 +% +%HISTORY_OUTPUT= (ITER, RMS_RES, HEAT, LINSOL) +HISTORY_OUTPUT= (HEAT) +MARKER_MONITORING= ( inner_pin ) +%MARKER_ANALYZE= ( inner_pin ) + diff --git a/TestCases/disc_adj_fsi/Airfoil_2d/config.cfg b/TestCases/disc_adj_fsi/Airfoil_2d/config.cfg index f545d1bfb53..818f359cdac 100755 --- a/TestCases/disc_adj_fsi/Airfoil_2d/config.cfg +++ b/TestCases/disc_adj_fsi/Airfoil_2d/config.cfg @@ -7,6 +7,8 @@ MARKER_ZONE_INTERFACE= (pressure_side,pressure_side_s, suction_side,suction_side CONSERVATIVE_INTERPOLATION= NO OUTER_ITER= 9 +OUTPUT_WRT_FREQ= 5 + MESH_FILENAME= mesh.su2 OBJECTIVE_FUNCTION= REFERENCE_NODE diff --git a/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg b/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg index 30dbb2dc246..b69b6d08132 100755 --- a/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg +++ b/TestCases/disc_adj_fsi/Airfoil_2d/configFEA.cfg @@ -44,7 +44,6 @@ MESH_FORMAT= SU2 RESTART_SOL= NO SOLUTION_FILENAME= solution_solid.dat SOLUTION_ADJ_FILENAME= adjoint_solid.dat -OUTPUT_WRT_FREQ= 999999 RESTART_FILENAME= solution_solid.dat RESTART_ADJ_FILENAME= adjoint_solid.dat % diff --git a/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg b/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg index 03ae5b6d85e..2dbad80c7b7 100755 --- a/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg +++ b/TestCases/disc_adj_fsi/Airfoil_2d/configFlow.cfg @@ -87,7 +87,6 @@ MESH_FORMAT= SU2 RESTART_SOL= NO SOLUTION_FILENAME= solution_fluid.dat SOLUTION_ADJ_FILENAME= adjoint_fluid.dat -OUTPUT_WRT_FREQ= 999999 RESTART_FILENAME= solution_fluid.dat RESTART_ADJ_FILENAME= adjoint_fluid.dat % diff --git a/TestCases/disc_adj_fsi/dyn_fsi/config.cfg b/TestCases/disc_adj_fsi/dyn_fsi/config.cfg new file mode 100755 index 00000000000..2f8810526ad --- /dev/null +++ b/TestCases/disc_adj_fsi/dyn_fsi/config.cfg @@ -0,0 +1,26 @@ +SOLVER= MULTIPHYSICS +MATH_PROBLEM= DISCRETE_ADJOINT +CONFIG_LIST=(configFlow.cfg, configFEA.cfg) + +MARKER_ZONE_INTERFACE= (pressure_side,pressure_side_s, suction_side,suction_side_s) + +CONSERVATIVE_INTERPOLATION= NO + +OUTER_ITER= 10 +MESH_FILENAME= mesh.su2 + +TIME_DOMAIN = YES +TIME_ITER = 3 +TIME_STEP = 0.01 +UNST_ADJOINT_ITER= 10 +ITER_AVERAGE_OBJ= 3 + +OBJECTIVE_FUNCTION= REFERENCE_NODE + +SCREEN_OUTPUT= OUTER_ITER, AVG_BGS_RES[0] + +WRT_ZONE_HIST=YES +%WRT_ZONE_CONV=YES + +% Debug: Force Zero Grid Velocity = NO +WRT_PERFORMANCE= NO diff --git a/TestCases/disc_adj_fsi/dyn_fsi/configFEA.cfg b/TestCases/disc_adj_fsi/dyn_fsi/configFEA.cfg new file mode 100755 index 00000000000..c657a817932 --- /dev/null +++ b/TestCases/disc_adj_fsi/dyn_fsi/configFEA.cfg @@ -0,0 +1,65 @@ +% Physics -------------------------------------------------------------- % +SOLVER= ELASTICITY +% +% Time settings --------------------------------------------------------- % +TIME_DISCRE_FEA= NEWMARK_IMPLICIT +NEWMARK_BETA=0.2601 +NEWMARK_GAMMA=0.52 +% +% Optimization --------------------------------------------------------- % +FEA_ADVANCED_MODE= YES +FEA_FILENAME= element_properties.dat +GRAD_OBJFUNC_FILENAME= of_grad.dat +REFERENCE_NODE= 234 +REFERENCE_NODE_DISPLACEMENT= (0.0, 0.0) +REFERENCE_NODE_PENALTY= 1.0 +DESIGN_VARIABLE_FEA= YOUNG_MODULUS +% +% Solid properties ----------------------------------------------------- % +MATERIAL_MODEL= NEO_HOOKEAN +ELASTICITY_MODULUS= 7E8 +POISSON_RATIO= 0.35 +MATERIAL_DENSITY= 2700.0 +% +% Boundary conditions -------------------------------------------------- % +MARKER_CLAMPED= ( clamped ) +MARKER_FLUID_LOAD= ( pressure_side_s, suction_side_s ) +% +% Solid numerics ------------------------------------------------------- % +GEOMETRIC_CONDITIONS= LARGE_DEFORMATIONS +FORMULATION_ELASTICITY_2D= PLANE_STRESS +% +% Linear solvers ------------------------------------------------------- % +LINEAR_SOLVER= CONJUGATE_GRADIENT +LINEAR_SOLVER_PREC= ILU +LINEAR_SOLVER_ERROR= 1E-8 +LINEAR_SOLVER_ITER= 1000 +DISCADJ_LIN_SOLVER= CONJUGATE_GRADIENT +DISCADJ_LIN_PREC= ILU +% +% Convergence criteria ------------------------------------------------- % +BGS_RELAXATION= FIXED_PARAMETER +STAT_RELAX_PARAMETER= 1.0 +INNER_ITER= 11 +% Incremental load on to test that it does not break the discadj, it should only affect the direct solution. +INCREMENTAL_LOAD= NO +% +% In\Out --------------------------------------------------------------- % +MESH_FILENAME= mesh.su2 +MESH_FORMAT= SU2 +% +RESTART_SOL= NO +SOLUTION_FILENAME= solution_solid.dat +SOLUTION_ADJ_FILENAME= adjoint_solid.dat +OUTPUT_WRT_FREQ= 1 +RESTART_FILENAME= solution_solid.dat +RESTART_ADJ_FILENAME= adjoint_solid.dat +% +TABULAR_FORMAT= CSV +VOLUME_FILENAME= solid +VOLUME_ADJ_FILENAME= adjoint_solid +% +SCREEN_WRT_FREQ_INNER= 10 +CONV_FILENAME= history +HISTORY_OUTPUT= ITER, RMS_RES, STRUCT_COEFF, TAVG_STRUCT_COEFF +OUTPUT_FILES= NONE diff --git a/TestCases/disc_adj_fsi/dyn_fsi/configFlow.cfg b/TestCases/disc_adj_fsi/dyn_fsi/configFlow.cfg new file mode 100755 index 00000000000..04cf4c83c6e --- /dev/null +++ b/TestCases/disc_adj_fsi/dyn_fsi/configFlow.cfg @@ -0,0 +1,102 @@ +% Physics -------------------------------------------------------------- % +SOLVER= EULER +KIND_TURB_MODEL= NONE +% +% Time settings --------------------------------------------------------- % +TIME_MARCHING= DUAL_TIME_STEPPING-2ND_ORDER +% +% Optimization --------------------------------------------------------- % +GRAD_OBJFUNC_FILENAME= of_grad.dat +% +% Compressible free-stream conditions ---------------------------------- % +MACH_NUMBER= 0.8 +AOA= 5.0 +INIT_OPTION= TD_CONDITIONS +FREESTREAM_OPTION= TEMPERATURE_FS +FREESTREAM_PRESSURE= 101325.0 +FREESTREAM_TEMPERATURE= 273.15 +REYNOLDS_LENGTH= 0.5 +% +% Fluid properties ----------------------------------------------------- % +FLUID_MODEL= IDEAL_GAS +GAMMA_VALUE= 1.4 +GAS_CONSTANT= 287.87 +VISCOSITY_MODEL= CONSTANT_VISCOSITY +MU_CONSTANT= 1.716E-5 +% +% Boundary conditions -------------------------------------------------- % +MARKER_FAR= ( farfield ) +MARKER_EULER= ( leading_edge, pressure_side, suction_side) +MARKER_DEFORM_MESH= ( leading_edge, pressure_side, suction_side ) +DEFORM_MESH= YES +% +% Post processing and monitoring --------------------------------------- % +REF_ORIGIN_MOMENT_X= -0.125 +REF_ORIGIN_MOMENT_Y= 0.00 +REF_ORIGIN_MOMENT_Z= 0.00 +REF_LENGTH= 0.5 +REF_AREA= 0.5 +MARKER_PLOTTING= ( leading_edge, pressure_side, suction_side ) +MARKER_MONITORING= ( leading_edge, pressure_side, suction_side ) +MARKER_DESIGNING= ( leading_edge, pressure_side, suction_side ) +% +% Common numerics settings --------------------------------------------- % +REF_DIMENSIONALIZATION= DIMENSIONAL +NUM_METHOD_GRAD= GREEN_GAUSS +CFL_NUMBER= 1000.0 +% +% Flow numerics -------------------------------------------------------- % +CONV_NUM_METHOD_FLOW= JST +JST_SENSOR_COEFF= ( 0.5, 0.02 ) +TIME_DISCRE_FLOW= EULER_IMPLICIT +% +% Linear solvers ------------------------------------------------------- % +LINEAR_SOLVER= BCGSTAB +LINEAR_SOLVER_PREC= ILU +LINEAR_SOLVER_ERROR= 1E-6 +LINEAR_SOLVER_ITER= 25 +DISCADJ_LIN_SOLVER= SMOOTHER +DISCADJ_LIN_PREC= ILU +LINEAR_SOLVER_SMOOTHER_RELAXATION= 0.7 +% Multigrid +MGLEVEL= 0 +NEWTON_KRYLOV= YES +QUASI_NEWTON_NUM_SAMPLES= 999 +% +DEFORM_LINEAR_SOLVER= CONJUGATE_GRADIENT +DEFORM_LINEAR_SOLVER_PREC= ILU +DEFORM_LINEAR_SOLVER_ERROR= 1e-8 +DEFORM_LINEAR_SOLVER_ITER= 1000 +DEFORM_STIFFNESS_TYPE= INVERSE_VOLUME +DEFORM_POISSONS_RATIO= 1e6 +% +% Convergence criteria ------------------------------------------------- % +% interaction +BGS_RELAXATION= FIXED_PARAMETER +STAT_RELAX_PARAMETER= 1.0 +% fluid +INNER_ITER= 31 +CONV_STARTITER= 0 +CONV_RESIDUAL_MINVAL= -7 +% +% In\Out --------------------------------------------------------------- % +MESH_FILENAME= mesh.su2 +MESH_FORMAT= SU2 +% +RESTART_SOL= NO +SOLUTION_FILENAME= solution_fluid.dat +SOLUTION_ADJ_FILENAME= adjoint_fluid.dat +OUTPUT_WRT_FREQ= 1 +RESTART_FILENAME= solution_fluid.dat +RESTART_ADJ_FILENAME= adjoint_fluid.dat +% +TABULAR_FORMAT= CSV +VOLUME_FILENAME= fluid +VOLUME_ADJ_FILENAME= adjoint_fluid +SURFACE_FILENAME= surface_fluid +SURFACE_ADJ_FILENAME= adjoint_surface_fluid +% +SCREEN_WRT_FREQ_INNER= 10 +CONV_FILENAME= history +HISTORY_OUTPUT= ITER, RMS_RES, AERO_COEFF, TAVG_AERO_COEFF +OUTPUT_FILES= NONE diff --git a/TestCases/disc_adj_fsi/dyn_fsi/grad_dv.opt.ref b/TestCases/disc_adj_fsi/dyn_fsi/grad_dv.opt.ref new file mode 100644 index 00000000000..3bcc2d6eedf --- /dev/null +++ b/TestCases/disc_adj_fsi/dyn_fsi/grad_dv.opt.ref @@ -0,0 +1,9 @@ +INDEX GRAD +0 -3.461460672772851e-03 +1 -1.841786315630031e-03 +2 -7.915536278471477e-04 +3 -2.739622075935052e-04 +4 -2.734869089862929e-04 +5 -7.881162336341228e-04 +6 -1.828978274796512e-03 +7 -3.427219375030697e-03 diff --git a/TestCases/hybrid_regression.py b/TestCases/hybrid_regression.py index fb06b8d5a6a..af6011b0eaf 100644 --- a/TestCases/hybrid_regression.py +++ b/TestCases/hybrid_regression.py @@ -646,7 +646,7 @@ def main(): fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" fsi2d.cfg_file = "configFSI.cfg" fsi2d.test_iter = 4 - fsi2d.test_vals = [4.000000, 0.000000, -3.768521, -4.159940] + fsi2d.test_vals = [4, 0, -3.743230, -4.133462] fsi2d.multizone= True fsi2d.unsteady = True test_list.append(fsi2d) @@ -656,7 +656,7 @@ def main(): stat_fsi.cfg_dir = "fea_fsi/stat_fsi" stat_fsi.cfg_file = "config.cfg" stat_fsi.test_iter = 7 - stat_fsi.test_vals = [-3.242851, -4.866383, 0.000000, 11.000000] + stat_fsi.test_vals = [-3.242851, -4.866383, 0.000000, 11] stat_fsi.multizone = True test_list.append(stat_fsi) @@ -665,7 +665,7 @@ def main(): dyn_fsi.cfg_dir = "fea_fsi/dyn_fsi" dyn_fsi.cfg_file = "config.cfg" dyn_fsi.test_iter = 4 - dyn_fsi.test_vals = [-4.398527, -4.086735, 0.000000, 121.000000] + dyn_fsi.test_vals = [-4.355806, -4.060581, 5.3837e-08, 100] dyn_fsi.multizone = True dyn_fsi.unsteady = True test_list.append(dyn_fsi) diff --git a/TestCases/parallel_regression.py b/TestCases/parallel_regression.py index b0c92bcb386..77faa7d3ecf 100644 --- a/TestCases/parallel_regression.py +++ b/TestCases/parallel_regression.py @@ -1175,7 +1175,7 @@ def main(): fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" fsi2d.cfg_file = "configFSI.cfg" fsi2d.test_iter = 4 - fsi2d.test_vals = [4, 0, -3.768496, -4.159961] #last 4 columns + fsi2d.test_vals = [4, 0, -3.743210, -4.133483] #last 4 columns fsi2d.su2_exec = "parallel_computation_fsi.py -f" fsi2d.timeout = 1600 fsi2d.multizone= True @@ -1200,7 +1200,7 @@ def main(): dyn_fsi.cfg_dir = "fea_fsi/dyn_fsi" dyn_fsi.cfg_file = "config.cfg" dyn_fsi.test_iter = 4 - dyn_fsi.test_vals = [-4.398550, -4.086739, 0.000000, 117.000000] + dyn_fsi.test_vals = [-4.355829, -4.060587, 5.3837e-08, 98] dyn_fsi.multizone = True dyn_fsi.unsteady = True dyn_fsi.su2_exec = "mpirun -n 2 SU2_CFD" @@ -1252,19 +1252,6 @@ def main(): cht_incompressible.tol = 0.00001 test_list.append(cht_incompressible) - # CHT incompressible unsteady - cht_incompressible_unsteady = TestCase('cht_incompressible_unsteady') - cht_incompressible_unsteady.cfg_dir = "coupled_cht/incomp_2d_unsteady" - cht_incompressible_unsteady.cfg_file = "cht_2d_3cylinders.cfg" - cht_incompressible_unsteady.test_iter = 2 - cht_incompressible_unsteady.test_vals = [-1.305471, -0.080372, -0.080376, -0.080372] #last 4 columns - cht_incompressible_unsteady.su2_exec = "mpirun -n 2 SU2_CFD" - cht_incompressible_unsteady.timeout = 1600 - cht_incompressible_unsteady.multizone = True - cht_incompressible_unsteady.unsteady = True - cht_incompressible_unsteady.tol = 0.00001 - test_list.append(cht_incompressible_unsteady) - # CHT compressible cht_compressible = TestCase('cht_compressible') cht_compressible.cfg_dir = "coupled_cht/comp_2d" @@ -1356,7 +1343,7 @@ def main(): pywrapper_fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" pywrapper_fsi2d.cfg_file = "configFSI.cfg" pywrapper_fsi2d.test_iter = 4 - pywrapper_fsi2d.test_vals = [4, 0, -3.768496, -4.159961] #last 4 columns + pywrapper_fsi2d.test_vals = [4, 0, -3.743210, -4.133483] #last 4 columns pywrapper_fsi2d.su2_exec = "mpirun -np 2 SU2_CFD.py --nZone 2 --fsi True --parallel -f" pywrapper_fsi2d.timeout = 1600 pywrapper_fsi2d.unsteady = True @@ -1382,7 +1369,7 @@ def main(): pywrapper_rigidMotion.cfg_dir = "py_wrapper/flatPlate_rigidMotion" pywrapper_rigidMotion.cfg_file = "flatPlate_rigidMotion_Conf.cfg" pywrapper_rigidMotion.test_iter = 5 - pywrapper_rigidMotion.test_vals = [-1.551335, 2.295594, 0.350036, 0.093081] + pywrapper_rigidMotion.test_vals = [-1.614170, 2.242953, 0.350036, 0.093137] pywrapper_rigidMotion.su2_exec = "mpirun -np 2 python launch_flatPlate_rigidMotion.py --parallel -f" pywrapper_rigidMotion.timeout = 1600 pywrapper_rigidMotion.tol = 0.00001 diff --git a/TestCases/parallel_regression_AD.py b/TestCases/parallel_regression_AD.py index 481838842eb..bb4813591a1 100644 --- a/TestCases/parallel_regression_AD.py +++ b/TestCases/parallel_regression_AD.py @@ -335,6 +335,19 @@ def main(): da_sp_pinArray_cht_2d_dp_hf.multizone = True test_list.append(da_sp_pinArray_cht_2d_dp_hf) + # 2D unsteady CHT vortex shedding at RE=200. TAVG_Temperature OF + da_unsteadyCHT_cylinder = TestCase('da_unsteadyCHT_cylinder') + da_unsteadyCHT_cylinder.cfg_dir = "coupled_cht/disc_adj_unsteadyCHT_cylinder" + da_unsteadyCHT_cylinder.cfg_file = "chtMaster.cfg" + da_unsteadyCHT_cylinder.test_iter = 2 + da_unsteadyCHT_cylinder.test_vals = [-3.521358, -4.312658, -4.271025, -9.846075, -7.967741, 0.0000e+00, 3.6840e+00, 2.9483e-01] + da_unsteadyCHT_cylinder.su2_exec = "mpirun -n 2 SU2_CFD_AD" + da_unsteadyCHT_cylinder.timeout = 1600 + da_unsteadyCHT_cylinder.tol = 0.00001 + da_unsteadyCHT_cylinder.unsteady = True + da_unsteadyCHT_cylinder.multizone = True + test_list.append(da_unsteadyCHT_cylinder) + ###################################### ### RUN TESTS ### ###################################### @@ -407,6 +420,23 @@ def main(): pass_list.append(naca_restart_shape_opt.run_opt()) test_list.append(naca_restart_shape_opt) + #################################################################### + ### Unsteady Disc. Adj. Coupled FSI ### + #################################################################### + + # Unsteady multi physics framework + dyn_discadj_fsi = TestCase('dyn_discadj_fsi') + dyn_discadj_fsi.cfg_dir = "disc_adj_fsi/dyn_fsi" + dyn_discadj_fsi.cfg_file = "config.cfg" + dyn_discadj_fsi.test_iter = 2 + dyn_discadj_fsi.su2_exec = "mpirun -n 2 SU2_CFD_AD" + dyn_discadj_fsi.timeout = 1600 + dyn_discadj_fsi.reference_file = "grad_dv.opt.ref" + dyn_discadj_fsi.test_file = "grad_young.opt" + dyn_discadj_fsi.unsteady = True + pass_list.append(dyn_discadj_fsi.run_filediff()) + test_list.append(dyn_discadj_fsi) + # Tests summary print('==================================================================') print('Summary of the parallel tests') diff --git a/TestCases/serial_regression.py b/TestCases/serial_regression.py index 98fd0feb499..040d9fba020 100644 --- a/TestCases/serial_regression.py +++ b/TestCases/serial_regression.py @@ -1319,7 +1319,7 @@ def main(): fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" fsi2d.cfg_file = "configFSI.cfg" fsi2d.test_iter = 4 - fsi2d.test_vals = [4, 0, -3.768501, -4.159959] #last 4 columns + fsi2d.test_vals = [4, 0, -3.743214, -4.133482] #last 4 columns fsi2d.su2_exec = "SU2_CFD" fsi2d.timeout = 1600 fsi2d.multizone = True @@ -1356,7 +1356,7 @@ def main(): dyn_fsi.cfg_dir = "fea_fsi/dyn_fsi" dyn_fsi.cfg_file = "config.cfg" dyn_fsi.test_iter = 4 - dyn_fsi.test_vals = [-4.398530, -4.086741, 0.000000, 101.000000] #last 4 columns + dyn_fsi.test_vals = [-4.355809, -4.060588, 5.3837e-08, 86] #last 4 columns dyn_fsi.multizone = True dyn_fsi.unsteady = True dyn_fsi.su2_exec = "SU2_CFD" @@ -1416,19 +1416,6 @@ def main(): cht_incompressible.tol = 0.00001 test_list.append(cht_incompressible) - # CHT incompressible unsteady - cht_incompressible_unsteady = TestCase('cht_incompressible_unsteady') - cht_incompressible_unsteady.cfg_dir = "coupled_cht/incomp_2d_unsteady" - cht_incompressible_unsteady.cfg_file = "cht_2d_3cylinders.cfg" - cht_incompressible_unsteady.test_iter = 2 - cht_incompressible_unsteady.test_vals = [-1.303588, -0.080377, -0.080380, -0.080377] #last 4 columns - cht_incompressible_unsteady.su2_exec = "SU2_CFD" - cht_incompressible_unsteady.timeout = 1600 - cht_incompressible_unsteady.multizone = True - cht_incompressible_unsteady.unsteady = True - cht_incompressible_unsteady.tol = 0.00001 - test_list.append(cht_incompressible_unsteady) - # CHT compressible cht_incompressible = TestCase('cht_compressible') cht_incompressible.cfg_dir = "coupled_cht/comp_2d" @@ -1874,7 +1861,7 @@ def main(): pywrapper_fsi2d.cfg_dir = "fea_fsi/WallChannel_2d" pywrapper_fsi2d.cfg_file = "configFSI.cfg" pywrapper_fsi2d.test_iter = 4 - pywrapper_fsi2d.test_vals = [4, 0, -3.768501, -4.159959] #last 4 columns + pywrapper_fsi2d.test_vals = [4, 0, -3.743214, -4.133482] #last 4 columns pywrapper_fsi2d.su2_exec = "SU2_CFD.py --nZone 2 --fsi True -f" pywrapper_fsi2d.new_output = True pywrapper_fsi2d.unsteady = True @@ -1903,7 +1890,7 @@ def main(): pywrapper_rigidMotion.cfg_dir = "py_wrapper/flatPlate_rigidMotion" pywrapper_rigidMotion.cfg_file = "flatPlate_rigidMotion_Conf.cfg" pywrapper_rigidMotion.test_iter = 5 - pywrapper_rigidMotion.test_vals = [-1.551335, 2.295594, 0.350050, 0.093081] + pywrapper_rigidMotion.test_vals = [-1.614170, 2.242953, 0.350050, 0.093137] pywrapper_rigidMotion.su2_exec = "python launch_flatPlate_rigidMotion.py -f" pywrapper_rigidMotion.new_output = True pywrapper_rigidMotion.timeout = 1600 diff --git a/TestCases/serial_regression_AD.py b/TestCases/serial_regression_AD.py index 2595dc80540..6b24acb58da 100644 --- a/TestCases/serial_regression_AD.py +++ b/TestCases/serial_regression_AD.py @@ -210,7 +210,7 @@ def main(): unst_deforming_naca0012.cfg_dir = "disc_adj_euler/naca0012_pitching_def" unst_deforming_naca0012.cfg_file = "inv_NACA0012_pitching_deform_ad.cfg" unst_deforming_naca0012.test_iter = 4 - unst_deforming_naca0012.test_vals = [-1.864178, -1.742176, 1090.300000, 0.000006] + unst_deforming_naca0012.test_vals = [-1.958006, -1.841808, 1081.700000, 0.000004] unst_deforming_naca0012.su2_exec = "SU2_CFD_AD" unst_deforming_naca0012.timeout = 1600 unst_deforming_naca0012.tol = 0.00001 diff --git a/TestCases/tutorials.py b/TestCases/tutorials.py index 8ae969d93c7..01bf850b4e2 100644 --- a/TestCases/tutorials.py +++ b/TestCases/tutorials.py @@ -42,6 +42,20 @@ def main(): ### RUN TUTORIAL CASES ### ###################################### + + # CHT incompressible unsteady + cht_incompressible_unsteady = TestCase('cht_incompressible_unsteady') + cht_incompressible_unsteady.cfg_dir = "../Tutorials/multiphysics/unsteady_cht/" + cht_incompressible_unsteady.cfg_file = "cht_2d_3cylinders.cfg" + cht_incompressible_unsteady.test_iter = 2 + cht_incompressible_unsteady.test_vals = [-2.659390, -2.533160, -0.080399, -0.080399, -0.080399, -12.421450, 0.0000e+00, 0.0000e+00, 2.3824e+02] #last 9 columns + cht_incompressible_unsteady.su2_exec = "mpirun -n 2 SU2_CFD" + cht_incompressible_unsteady.timeout = 1600 + cht_incompressible_unsteady.multizone = True + cht_incompressible_unsteady.unsteady = True + cht_incompressible_unsteady.tol = 0.00001 + test_list.append(cht_incompressible_unsteady) + ### Incompressible Flow # 2D pin case massflow periodic with heatflux BC and prescribed extracted outlet heat diff --git a/UnitTests/Common/simple_ad_test.cpp b/UnitTests/Common/simple_ad_test.cpp index 6e95b218bb4..49d18467f43 100644 --- a/UnitTests/Common/simple_ad_test.cpp +++ b/UnitTests/Common/simple_ad_test.cpp @@ -56,5 +56,5 @@ TEST_CASE("Simple AD Test", "[AD tests]") { AD::ComputeAdjoint(); CHECK(SU2_TYPE::GetValue(y) == Approx(64)); - CHECK(SU2_TYPE::GetDerivative(y) == Approx(48)); + CHECK(SU2_TYPE::GetDerivative(x) == Approx(48)); } diff --git a/UnitTests/Common/toolboxes/ndflattener_tests.cpp b/UnitTests/Common/toolboxes/ndflattener_tests.cpp new file mode 100644 index 00000000000..9ec4440e8e6 --- /dev/null +++ b/UnitTests/Common/toolboxes/ndflattener_tests.cpp @@ -0,0 +1,140 @@ +/*! + * \file ndflattener_tests.cpp + * \brief Unit tests for NdFlattener template classes. + * \author M. Aehle + * \version 7.1.1 "Blackbird" + * + * SU2 Project Website: https://su2code.github.io + * + * The SU2 Project is maintained by the SU2 Foundation + * (http://su2foundation.org) + * + * Copyright 2012-2021, 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 "catch.hpp" +#include "../../Common/include/toolboxes/ndflattener.hpp" + +TEST_CASE("NdFlattener Test", "[NdFlattener]"){ + + int rank; SU2_MPI::Comm_rank(SU2_MPI::GetComm(), &rank); + int size; SU2_MPI::Comm_size(SU2_MPI::GetComm(), &size); + + /*-- Provide non-flat array --*/ + su2double** A = new su2double*[2]; + A[0] = new su2double[2]; A[0][0] = 0.0; A[0][1] = 1.0; + A[1] = new su2double[3+rank]; + for(int i=0; i<3+rank; i++) + A[1][i] = 2.0 + rank + i; + + /*-- Accessor --*/ + auto f = std::make_pair( (size_t)2, [rank,A](int i) { + return std::make_pair( (size_t)(i==0?2:(3+rank)), [rank,A,i](int j){ + return A[i][j]; + }); + }); + + /*-- Read into flattening structure --*/ + NdFlattener<2> nd2; + nd2.initialize_or_refresh(f); + + /*-- Modify A -> this should not alter nd2 at this point --*/ + A[0][0] = 0.5; + + /*-- Check structure --*/ + REQUIRE( nd2.size() == 2 ); + REQUIRE( nd2[0][0] == 0.0 ); + REQUIRE( nd2[0][1] == 1.0 ); + REQUIRE( nd2[1].size() == 3 + rank ); + for(int i=0; i<3+rank; i++){ + REQUIRE( nd2[1][i] == 2.0 + rank + i ); + } + + /*-- Modify structure. --*/ + nd2[0][0] = 0.7; + nd2[0].data()[1] = 1.7; + + /*-- gather flattening structures of all processes --*/ + NdFlattener<3> nd3(Nd_MPI_Environment(), nd2); + + /*-- Check gathered structure, non-const look-up. --*/ + REQUIRE( nd3.size() == size ); + for(int r=0; r& nd3_const = nd3; + REQUIRE( nd3_const.size() == size ); + for(int r=0; r a1( + std::make_pair( (size_t)(3+rank), [rank,A](int i) { + return (unsigned long)(2+rank+i); + }) + ); + const NdFlattener<1, unsigned long>& a1_const = a1; + REQUIRE( a1.size() == 3 + rank ); + for(int i=0; i<3+rank; i++){ + REQUIRE( a1[i] == 2 + rank + i ); + REQUIRE( a1_const[i] == 2 + rank + i ); + } + a1[0] = 1; + REQUIRE( a1_const.data()[0] == 1 ); + a1.data()[0] = 2 + rank; + REQUIRE( a1_const[0] == 2 + rank ); + const NdFlattener<2, unsigned long> a2_const(Nd_MPI_Environment(MPI_UNSIGNED_LONG), a1); + REQUIRE( a2_const.size() == size ); + for(int r=0; r